View Source

In [Kotlin], everything is an object in the sense that one can call member functions and properties on any variable. Some types are built-in, because their implementation is optimized, but for the used they look like ordinary classes. In this section we describe most of these types: [numbers|#Numbers], [characters|#Characters], [booleans|#Booleans] and [arrays|#Arrays].

h3. Numbers

[Kotlin] handles numbers in a way close to *Java*, but not exactly the same. For example, there are no _implicit widening conversions_ or numbers, and literals are slightly different in some cases.

[Kotlin] provides the following built-in types representing numbers (this is close to *Java*):
|| Type || Bitwidth ||
| Double | 64 |
| Float | 32 |
| Long | 64 |
| Int | 32 |
| Short | 16 |
| Byte | 8 |

Note that [characters|#Characters] are not numbers in [Kotlin].

h4. Representation

On the *Java* platform, numbers are physically stored as JVM primitive types, unless we need a [nullable|Null-safety] number reference (e.g. {{Int?}}) or generics are involved. In the latter cases numbers are _boxed_.

*Note* that boxing of numbers does not preserve [identity|Basic operations]:
{jet}
val a : Int = 10000
print(a identityEquals a) // Prints 'true'
val boxedA : Int? = a
val anotherBoxedA : Int? = a
print(boxedA identityEquals anotherBoxedA) // !!!Prints 'false'!!!
{jet}
On the other hand, it preserves [equality|Expressions#Equality checks]:
{jet}
val a : Int = 10000
print(a == a) // Prints 'true'
val boxedA : Int? = a
val anotherBoxedA : Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'
{jet}

h4. Explicit conversions

Due to different representations, smaller types are not _subtypes_ of bigger ones.
If they were, we would have troubles of the following sort:
{jet}
// 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(a == b) // Surprise! This prints "false" as Long's equals() check for other part to be Long as well
{jet}
So not only identity, but even equality would have been lost silently all over the place.

As a consequence, smaller types are *NOT* implicitly converted to bigger types. This means that one cannot assign a value of type {{Byte}} to an {{Integer}} variable without an explicit conversion:
{jet}
val b : Byte = 1 // OK, literals are checked statically
val i : Int = <error desc="Incompatible types: Byte cannot be assigned to a variable of type Int. Use the explicit conversion '.toInt()'">b</error> // ERROR
{jet}
One can use *explicit conversions* to widen numbers:
{jet}
val i : Int = b.toInt() // OK: explicitly widened
{jet}

Every number type supports the following conversions:
* {{toByte() : Byte}}
* {{toShort() : Short}}
* {{toInt() : Int}}
* {{toLong() : Long}}
* {{toFloat() : Float}}
* {{toDouble() : Double}}
* {{toChar() : Char}}

Absence of implicit conversions is rarely noticeable because one can use literals almost freely cause the type is inferred from the context, and arithmetical operations are _overloaded_ for appropriate conversions, for example
{jet}
val l = 1.toLong() + 3 // Long + Int => Long
{jet}

h4. Literals

All the integer literals are written in the same way:
* Decimals: {{123}}, {{123L}}, {{123.5}}, {{123.5e10}}, {{123.5f}}
* Hexadecimals: {{0x0F}}
* Binaries: {{0b00001011}}

*NOTE*: Octal literals are not supported.

You can only use a capital "L" for suffixing {{Long}} values (little "l" looks too much like "1" in many fonts), both "F" and "f" are allowed for {{Float}}'s. Alternatively, one could use explicit conversions to specify a type for a literal:
{jet}
val list = list(1.toLong(), 100000000000, 2.toLong())
{jet}

h4. Operations

[Kotlin] supports the standard set of arithmetical operations over numbers, which are declared as members of appropriate classes (but the compiler optimizes the calls down to the corresponding instructions). See [Operator overloading|Functions#Operator overloading].

As of _bitwise_ operations, there're no special characters for them, but just named functions that can be called in [infix form|Functions#Infix calls], for example:
{jet}
val x = (1 shl 2) and 0x000FF000
{jet}
Here is the complete list of bitwise operations (available for {{Int}} and {{Long}} only):
* {{shl(bits)}} -- signed shift left (*Java*'s {{<<}})
* {{shr(bits)}} -- signed shift right (*Java*'s {{>>}})
* {{ushr(bits)}} -- unsigned shift right (*Java*'s {{>>>}})
* {{and(bits)}} -- bitwise {{and}}
* {{or(bits)}} -- bitwise {{or}}
* {{xor(bits)}} -- bitwise {{xor}}
* {{inv()}} -- bitwise inversion

h2. Characters

Characters are represented by the type {{Char}}. They are can not be treated directly as numbers:
{jet}
fun check(c : Char) {
if (c <error desc="A value of type Char cannot be equal to a value of type Int">==</error> 1) { // ERROR: incompatible types
// ...
}
}
{jet}
Character literals go in single quotes: {{'1'}}, {{'\n'}}, {{'\uFF00'}}.
One can explicitly _convert_ a character to an {{Int}} number:
{jet}
fun decimalDigitValue(c : Char) : Int {
if (c !in '0'..'9')
throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}
{jet}

Like numbers, characters are *boxed* when a nullable reference is needed. Identity is not preserved by the boxing operation.

h2. Booleans

The type {{Boolean}} represents booleans, and has two values: {{true}} and {{false}}.

Booleans are boxed if a nullable reference is needed.

Built-in operations on booleans include
* {{\|\|}} -- lazy disjunction
* {{&&}} -- lazy conjunction

h3. Arrays

Arrays in [Kotlin] are represented by the {{Array}} class, that has {{get}} and {{set}} functions (that turn into {{\[\]}} by [operator overloading conventions|Operator overloading]), and {{size}}, along with a few other useful member functions:
{jet}
class Array<T>(val size : Int, init : (Int) -> T) {
fun get(index : Int) : T
fun set(index : Int, value : T) : Unit

fun iterator() : Iterator<T>

val indices : IntRange
}
{jet}

To create an array one can call its [constructor|Classes and Inheritance#Classes and Primary constructors] providing the array size and a [function|Function literals] that knows how to initialize elements of the array:
{jet}
val asc = Array<Int>(5, {i -> i * i}) // Creates an array [0, 1, 4, 9, 16]
{jet}
Or, alternatively, one can use a library function {{array()}} and pass the item values to it, so that {{array(1, 2, 3)}} creates an array {{\[1, 2, 3\]}}.

As we said above, the {{\[\]}} operation stands for calls to member functions {{get()}} and {{set()}}. When compiling to JVM byte codes, the compiler optimizes access to arrays so that there's no overhead introduced, and all operations work exactly like in *Java*:
{jet}
val array = array(1, 2, 3, 4)
array[x] = array[x] * 2 // no actual calls to get() and set() generated
for (x in array) // no iterator created
print(x)
{jet}
Even when we navigate with an index, it does not introduce any overhead:
{jet}
for (i in array.indices) // no iterator created
array[i] += 2
{jet}
Finally, *in*\-checks have no overhead either
{jet}
if (i in array.indices) { // same as (i >= 0 && i < array.size)
print(array[i])
}
{jet}

*Note*: arrays are [invariant|Java interoperability#Arrays]. For the best performance on the JVM use [specialized array classes|Java interoperability#Arrays].

h3. What's next

* [Strings]