`val a = 0 ?: 0.1`


#1

From the source code, I learn that Number is “Superclass for all platform classes representing numeric values”.

1.We can say Number’s Value, but we cannot say Value’s Number.
So value is a property of number.
2.A number should be comparable.

interface Value
interface Comparable
abstract class Number : Value, Comparable

then:
val a = 0 ?: 0.1 // a is Number
better than:
val a = 0 ?: 0.1 // a is Any

I’m not going to change the API.
I just want to ask if it’s right that I comprehend.


#2

I am surely can’t understand a thing in your question. Number is a superclass for different numeric classes like Double, BigDecimal or even AtomicInteger. There is a reason why it is not comparable: comparison works different for different numeric representations, and you can’t predict how it will behave for custom numbers. If you are sure that all numbers in your program will behave as Doubles, you can add some useful extension functions for that. val a: Number = 0 is better than val a: Any = 0 because in first case you could call specific Number methods for a, in second cases it will be just generic object. In both cases actual object type will be Int. As for elvis operator ?:, I don’t undersnad what it means in your code. In Kotlin elvis is used only for nullables.


#3

Maybe I should write in this way, but val a = 0 ?: 0.1 actually works.

val value = 0
val a = value ?: 0.1 // a is Any

#4

Literally, a number can be compared to another number by its value.
just like 5 > 2.1
If you just want to represent a value, You can only implement Value interface.

I think the name of Number class is not a good name for represent its usage.


#5

And what do you expect it to do?

Please see the description of elvis operator in kotlin. You are trying to use it like in groovy, where groovy truth states that 0 == null, but event in groovy it does not make sense. In Kotlin it does not work at all. It probably compiles, but your value is never null so it does nothing.


#6

the value of Double and value of BigDecimal are very different values. There is no universal way to compare them. In my programs I frequently extend some of number properties like arithmetic operations, but it is not universal.


#7

I write that just for express my idea in one line, It’s not important.
And there is a difference, in val a = 0 ?: 0.1, a is Any in this case.


#8

A big decimal number can compare to another big decimal number.
A double number can also compare to another double number.


#9

They are already comparable. Though If you use a Number as a compile-time type, you do not know what specific implementation it will use. You can check it in run-time if you want like that:

fun Number.compareTo(bd: BigDecimal): Int{
  return when(this){
    is BigDecimal -> this.compareTo(bd) //using kotlin implicit cast
    else -> this.toDouble().compareTo(bd.toDouble())
  }
}

#10

Which version of Kotlin do you use? a is inferred to Int using 1.2.21 on try.kotlinlang.org


#11

mistype
val a = 0 ?: 0.1


#12

I just want to express number should be comparable literally.
So the name of Number class is not a good name.


#13

I think the compiler gets confused because 0.1 is a primitive type. Even in the following case (which makes a bit more sense), the inferred type is Any:

val x: Int? = 0
val a = x ?: 0.1

But if you add an explicit type, it is not a problem to have a be a Number:

val x: Int? = 0
val a: Number = x ?: 0.1

I believe the compiler can be smarter here (if the type of the left operand of ?: is a nullable type, as a non-nullable type does not make sense in combination with ?:), and infer Number. You might want to create an issue in YouTrack if there is none for it yet.


#14

The name inherits Java Number. So no freedom there. I think that problem of comparison different numbers could be partially or completely solved by type-classes.

As for custom usage, you can write your own abstraction on top of numbers. For example I have an interface called Value that could wrap numbers, strings, booleans and Instants. Previously I was using a custom-made comparator for them using type of first argument to perform comparison, but I had to remove it since it basically violates comparable contract (should be commutative). So no I use external comparing function.


#15

public class Int private constructor() : Number(), Comparable<Int>

The compiler doesn’t know which it should point to, So it points to their parent Any(Any?).


#16

I do not know the type inference algorithm, but it looks like that it does not select Number because the subclasses also implement Comparable at the same inheritance level. I still feel that Number could be inferred, because Comparable<Int> and Comparable<Double> are not candidates because they are not implemented by both Int and Double. But somebody with more knowledge about the type inference has to provide the conclusive answer.

But this is all nitpicking about compiler behavior. What is the realistic problem you are trying to solve?


#17

Thanks.
I know we cannot change it.
So I said I was not going to change the API.
I just wanted to know if it’s right that I think.


#18

There is no problem I am going to solve. Haha, just for learning.