Preferring val and understanding Kotlin's type system is the foundation of idiomatic Kotlin.
Kotlin has two kinds of variables:
valis read-only: assigned once, like Java'sfinal. Prefer it by default.varis mutable and can be reassigned.
Types are usually inferred: val count = 3 is an Int, val price = 9.99 a Double. Declare explicitly with a colon: val ratio: Float = 0.5f. The type is fixed at compile time either way.
Basic types:
- Integers:
Byte,Short,Int(default),Long(3L). UnsignedUInt,ULongexist too. - Floating point:
Double(default),Float(1.5f). Boolean,Char('a'),String.
All of them are objects with methods (5.toString(), 3.coerceAtLeast(5)), but the compiler uses JVM primitives under the hood where possible, so there's no performance penalty.
Kotlin does no implicit widening between numeric types: an Int can't be assigned to a Long variable without toLong(). Use toInt(), toDouble() and friends. Integer division truncates (7 / 2 == 3); % is remainder. Readable literals use underscores: 1_000_000.
const val declares a compile-time constant at top level or in an object. Note that val makes the reference read-only, not the object: a val list = mutableListOf(1) can still be modified with add.
Example
const val MAX_USERS = 100
fun main() {
val name = "Ada" // String, read-only
var age = 36 // Int, mutable
age += 1
val big: Long = 3_000_000_000
val ratio = 7 / 2 // Int division
val exact = 7 / 2.0 // Double
println("$name $age $ratio $exact") // Ada 37 3 3.5
val i = 42
val l: Long = i.toLong() // no implicit widening
println(l + big) // 3000000042
println(MAX_USERS.coerceAtMost(50)) // 50
val list = mutableListOf(1)
list.add(2) // the val reference is fixed, contents are not
println(list) // [1, 2]
}Remember
- Use val by default, var only when reassignment is needed
- Types are inferred but static
- No implicit numeric widening: call toLong(), toDouble()...
- val makes the reference read-only, not the object
Watch out for
- Assuming val list = mutableListOf() is immutable.