In Kotlin, the Number
type sounds quite useful: A type to use whenever I need something numeric.
When actually using it, however, I quickly noticed it is pretty useless: I cannot use any operators on these numbers. As soon as I need to do something with them, I need to explicitly convert them (even for comparing).
Why did the language designers choose to not include operators in the Number
specification?
Thinking on this, I noticed it could be tricky to implement Number.plus(n: Number): Number
, because n
might be of a different type than this
.
On the other hand, such implementations do exist in all Number
subtypes I checked. And of course they are necessary if I want to type 1 + 1.2
, which calls Int.plus(d: Double): Double
The result for me is that I have to call .toDouble()
every time I use a number. This makes the code hard to read (compare a.toDouble() < b.toDouble()
with a < b
).
Is there any technical reason why operators where omitted from Number
?
The problem is the implementation of the compareTo
method. While it sounds reasonable and easy to add it in the first place, the devil lies in the details:
How would you compare instances of arbitrary Number
classes to each other? Kotlin could implement the compare method using toDouble()
; however this has problems with equality/precision: How do you compare a BigDecimal
to a Double
? Using toDouble()
on the BigDecimal
might lose precision, and two (actually different) BigDecimal
s might be considered equal using this method.
The mess gets even worse when you start to assume one or both types were supplied by libraries, where you cannot make assumptions on precision etc.
In Java, the Number
type is not Comparable
either.
Furthermore, some Number
values like NaN
might not be comparable at all.
If you need a Number
to be comparable, you can easily implement your own compareTo
-method as extension function. This has some additional limitations though, as most Number
subtypes implement Comparable
, and the extension function will lose against that implementation.
Credit for this answer goes to Roland, I only extended his comments (see on the question) into an answer.