curric

View on GitHub

./curric/kotlin/basics/Numbers/

Numbers

In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some of the types can have a special internal representation - for example, numbers, characters and booleans can be represented as primitive values at runtime - but to the user they look like ordinary classes. In this section we describe the basic types used in Kotlin: numbers, characters, booleans, arrays, and strings.

Explicit Conversion

Due to different representations, smaller types are not subtypes of bigger ones. If they were, we would have troubles of the following sort:

// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // implicit conversion yields a boxed Long (java.lang.Long)
print(b == a) // Surprise! 
/* This prints "false" as Long's equals() 
 * checks whether the other is Long as well
 */

So equality would have been lost silently all over the place, not to mention identity.

As a consequence, smaller types are NOT implicitly converted to bigger types. This means that we cannot assign a value of type Byte to an Int variable without an explicit conversion

val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR

We can use explicit conversions to widen numbers

val i: Int = b.toInt() // OK: explicitly widened
print(i)

Every number type supports the following conversions:

Absence of implicit conversions is rarely noticeable because the type is inferred from the context, and arithmetical operations are overloaded for appropriate conversions, for example

val l = 1L + 3 // Long + Int => Long

Division of Integers

Equality checks: a == b and a != b Comparison operators: a < b, a > b, a <= b, a >= b Range instantiation and range checks: a..b, x in a..b, x !in a..b

a..b is a Range type, this will be covered later

When the operands a and b are statically known to be Float or Double or their nullable counterparts (the type is declared or inferred or is a result of a smart cast), the operations on the numbers and the range that they form follow the IEEE 754 Standard for Floating-Point Arithmetic.

However, to support generic use cases and provide total ordering, when the operands are not statically typed as floating point numbers (e.g. Any, Comparable<...>, a type parameter), the operations use the equals and compareTo implementations for Float and Double, which disagree with the standard, so that: