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?
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).
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.
That would/could be more efficient as an inline class. ![]()
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.