4

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?

Qw3ry
  • 1,319
  • 15
  • 31
  • I think the biggest problem is, that `Number` is an abstract class and therefore allows custom implementations to be passed... how would you add a `BogusNumber` to any other `Number`? – Roland Aug 07 '19 at 10:52
  • by the way... please check [`BigDecimal#plus`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/java.math.-big-decimal/plus.html) ... for me it makes sense to not have all overloaded variants there... don't want that inaccuracy of adding float/doubles, etc. there ;-) – Roland Aug 07 '19 at 11:00
  • With `BogusNumber`: You could provide a default implementation with `toDouble()`. But even if you omit `plus`, at least a `compareTo` would be _so_ useful – Qw3ry Aug 07 '19 at 11:04
  • 3
    Have a look at `java.lang.Number` too. Kotlin's Number is not much different. – laalto Aug 07 '19 at 11:05
  • 1
    @Qw3ry the problem is, that if you would support such a `compareTo`, you could only support the types that you know about at that time... and everyone else might be fooled, because they think it is supported but it isn't really... note also that `toDouble()` might not be the best choice... think of `BigDecimal` again... you do not want to play (compare/add/etc.) with `Double` while operating on a `BigDecimal`. You can, but you usually don't want to... – Roland Aug 07 '19 at 11:10
  • 1
    Note also... if you really find it that useful, just add your own `fun Number.compareTo` extension function ;-) but then... just be aware that it might not always work the way you expect (in the end... `Number` is not derived from `Comparable`, but other numbers are... and extension functions lose against existing functions...) – Roland Aug 07 '19 at 11:19
  • Okay, I guess I got your point. Also related: https://stackoverflow.com/questions/480632/why-doesnt-java-lang-number-implement-comparable – Qw3ry Aug 07 '19 at 11:30

1 Answers1

0

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) BigDecimals 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.

Qw3ry
  • 1,319
  • 15
  • 31
  • You just took wrong example. Converting double to BigDecimal and comparing them would work. We just make simple assumption that 10 = 10.00. Numbers ARE comparable, because they come from so called MATH. Number.compare should be part of language. – Pavel Niedoba Nov 09 '21 at 15:51
  • Actually, it does not: https://pl.kotl.in/5vIBy2iDS – Qw3ry Nov 10 '21 at 08:55
  • Of course you can compare numbers in _MATH_. But programming is not simple math, because your numbers have different representations on storage, and might be imprecise. If you supply a `MyBestDecimal : Number` and a library you are using supplies some `OurBestDecimal : Number`, they might have arbitrary implementations of those classes, and with the methods given by `Number` you cannot compare them reliably – Qw3ry Nov 10 '21 at 09:01