Since we have null types, why not NaN?


#1

NaN and are almost as ugly and undesirable as null, except that they don’t explicitly throw errors. Why isn’t there a syntax to require a finite float value?


#2

Well, usability would be terrible. Having to check each float value to be finite would mean hundreds of unnecessary checks. I don’t want to know how complicated my code (which is quite math heavy) would be if I had to do all those checks. Also I guess performance would be much worse with all those extra checks (I don’t think they can be optimized away easily).


#3

You can define a class that checks for this in its init block, and defines operators etc.
Something like
class FiniteNumberException(message: String) : RuntimeException(message)

data class FiniteFloat(val value: Float) : Comparable<Number>, Number() {

    init{
        if(value.isInfinite())
            throw FiniteNumberException("Value $value is not finite")

        if(value.isNaN())
            throw FiniteNumberException("Value $value is NaN")
    }

    override fun toByte() = value.toByte()
    override fun toChar() = value.toChar()
    override fun toInt() = value.toInt()
    override fun toDouble() = value.toDouble()
    override fun toFloat() = value
    override fun toLong() = value.toLong()
    override fun toShort() = value.toShort()

    operator fun plus(other: FiniteFloat) = FiniteFloat(value + other.value)
    operator fun minus(other: FiniteFloat) = FiniteFloat(value - other.value)
    operator fun times(other: FiniteFloat) = FiniteFloat(value * other.value)
    operator fun div(other: FiniteFloat) = FiniteFloat(value / other.value)
    operator fun rem(other: FiniteFloat) = FiniteFloat(value % other.value)

    operator fun inc() = FiniteFloat(value + 1)
    operator fun dec() = FiniteFloat(value - 1)
    operator fun rangeTo(other: FiniteFloat) = value..other.value

    override fun compareTo(other: Number) = value.compareTo(FiniteFloat(other.toFloat()).value)

    operator fun plus(other: Number) = FiniteFloat(value + FiniteFloat(other.toFloat()).value)
    operator fun minus(other: Number) = FiniteFloat(value - FiniteFloat(other.toFloat()).value)
    operator fun times(other: Number) = FiniteFloat(value * FiniteFloat(other.toFloat()).value)
    operator fun div(other: Number) = FiniteFloat(value / FiniteFloat(other.toFloat()).value)
    operator fun rem(other: Number) = FiniteFloat(value % FiniteFloat(other.toFloat()).value)
    
    operator fun rangeTo(other: Number) = value..FiniteFloat(other.toFloat()).value
}

fun Number.toFiniteFloatOrNull() = try{ FiniteFloat(this.toFloat()) } catch (fne: FiniteNumberException) { null }
fun Number.toFiniteFloat() = FiniteFloat(this.toFloat())

Then you can do things like (3 + 4).toFiniteFloat() + 4.5.


#4

That would/could be more efficient as an inline class. :tada:


#5

Indeed it would… if inline classes could have init blocks. You could probably get around that by making the constructor internal and doing the checking in a creation method, but it wouldn’t be as clean.