What a data type is
Every value in a Kotlin program has a type, which says what kind of data it is and what you can do with it. The compiler checks types before the program runs, so it can refuse operations that make no sense. These are the five types you meet first:
| Type | Holds | Examples |
|---|---|---|
Int | whole numbers | 3, -12 |
Double | decimal numbers | 3.14, -0.5 |
String | text | "John Doe" |
Boolean | true or false | true, false |
Char | one character | 'a', 'Z', '?' |
Type names start with a capital letter. Int is right; int is not a Kotlin type. Strings use double quotes and a Char uses single quotes.
Why the type changes what code does
Look at this line, with no other context:
println(a + b)
What does it do? It depends on the types of a and b. With two numbers, + adds:
val a = 10
val b = -5
println(a + b) // 5
With two strings, + joins them:
val a = "Hello "
val b = "world!"
println(a + b) // Hello world!
Addition and concatenation are different operations. Kotlin picks the right one by looking at the types of the operands.
Invalid operations are caught
Types also stop you from doing nonsense. Multiplying two strings has no meaning:
val a = "peanut"
val b = "butter"
println(a * b)
Kotlin does not run this and fail halfway. It refuses to compile it:
error: unresolved reference 'times' for operator '*'.
The message means that String has no times function, which is what the * operator calls. The same checking applies to assignments: a variable declared as Int can't later be given a String or a decimal such as 5.5.
Nullability
By default, a type can never hold null, the marker for "no value". To allow it, add a question mark to the type: String? means "a String, or null".
val name: String? = null
println(name?.length) // prints null
println(name!!.length) // throws a NullPointerException
The safe call ?. gives null when the receiver is null instead of failing. The !! operator says "I am sure this is not null", and the program crashes if you are wrong. Writing plain name.length on a String? doesn't compile at all: the compiler reports that only safe or non-null asserted calls are allowed on a nullable receiver. So, in Kotlin, a missing value has to be dealt with in the code that uses it.
The exercise
The task builds four variables, one step at a time, each with an explicit type after the name:
myIntof typeInt, with a whole number.myFloatof typeDouble, with a decimal value. The name says float, but the type to use isDouble, Kotlin's default for decimals. The separateFloattype exists but needs anfsuffix on its values.myStringof typeString, with text in double quotes.myBoolof typeBoolean, withtrueorfalse.
Each variable is added below the previous ones, which stay in place:
val myInt: Int = 5
val myFloat: Double = 3.14
val myString: String = "Hello"
val myBool: Boolean = true
The pattern is val name: Type = value. The value has to fit the type: val myInt: Int = 3.14 fails, and so does val myString: String = 5.
Checking what type a value has
Literals get their type from how they are written. 42 is an Int, 3.14 is a Double, "42" is a String, 'a' is a Char and true is a Boolean. A whole-number literal too big for an Int, such as 3000000000, is automatically a Long.
You can ask a value at run time with is:
val x: Any = 3.14
println(x is Double) // true
println(x is Int) // false
Any is the type that accepts a value of any type, which makes it useful for this demonstration. In everyday code the compiler already knows the types, so you rarely need such a check.
Details that surprise beginners
- Integer division.
7 / 2is3, because both operands areInt.7.0 / 2is3.5. - No silent widening.
val d: Double = 5doesn't compile, even though 5 fits in a double. Write5.0, or convert withtoDouble(). - Range of
Int. AnInthas 32 bits, so the largest value is 2147483647, and adding 1 to it wraps around to -2147483648. The 64-bitLongtype is for bigger numbers. - Inference. You may leave the type out, as in
val myInt = 5, and Kotlin works it out. Writing it explicitly, as in this exercise, makes the intention visible.
Key takeaways
- Every value has a type:
Int,Double,String,Boolean,Char, and more. - The type decides what operators such as
+do and which operations are allowed. - Type mistakes are reported by the compiler before the program runs.
- Types don't allow
nullunless you add?.