Data Types Workbook
Eleven short exercises on Kotlin's basic types — val and var, the number types, explicit conversions, strings and templates, nullability, and Unit and Nothing.
Practice problems for In Kotlin, There Are No Primitives. Each takes a minute or two. A couple of exercises auto-check: implement the function in the editor and press Run — hidden tests go green when you’re right and red (with a hint) when you’re not, all on JetBrains’ Kotlin compiler server. The rest stay attempt-then-reveal: fill in the TODO, press Run, then click Show answer to check yourself. Nothing here is a trick question, just direct practice of the syntax from the lesson.
val, var, and the number types
1. Read-only and mutable
Declare a read-only name holding "Ada" and a mutable age holding 36, then reassign age to 37.
fun main() {
// TODO: read-only name = "Ada", mutable age = 36, then reassign age to 37
val name = ""
val age = 0
println(name + " " + age)
} Show answer Hide answer
val name = "Ada"
var age = 36
age = 37 2. Literals pick their type
Write literals for: a Long equal to 42, a Double equal to 3.14, and a Float equal to 3.14.
fun main() {
// TODO: write a Long = 42, a Double = 3.14, and a Float = 3.14
val l = 0
val d = 0.0
val f = 0.0
println(l.toString() + " " + d + " " + f)
} Show answer Hide answer
val l = 42L
val d = 3.14
val f = 3.14f 3. A readable big number
Write the literal 8100000000 as a Long with digit separators for readability.
fun main() {
// TODO: write 8100000000 as a Long with digit separators for readability
val population = 0L
println(population)
} Show answer Hide answer
val population = 8_100_000_000L 4. No implicit widening
This doesn’t compile: val l: Long = anInt. Fix it without changing anInt’s type.
fun main() {
val anInt = 42
// TODO: assign anInt to a Long without changing anInt's type
val l: Long = 0L
println(l)
} Show answer Hide answer
val l: Long = anInt.toLong()Kotlin never widens numeric types silently — you convert explicitly.
Char, strings, and templates
5. A character’s code
Implement charCode so it returns a character’s numeric code — for 'A', that’s 65.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun charCode() {
Assert.assertEquals("'A' has code 65", 65, charCode('A'))
Assert.assertEquals("'a' has code 97", 97, charCode('a'))
}
}
//sampleStart
fun charCode(c: Char): Int =
0 // TODO: return the character's numeric code
//sampleEnd Show answer Hide answer
fun charCode(c: Char) = c.codeChar is its own type, not a number, so you ask for the code rather than using it as one.
6. A string template
Given val age = 36, print Next year: 37 using a string template with an expression.
fun main() {
val age = 36
// TODO: print "Next year: 37" using a string template with an expression
println("Next year: ?")
} Show answer Hide answer
println("Next year: ${age + 1}") 7. A raw string
Write the Windows path C:\Users\ada as a string literal without escaping the backslashes.
fun main() {
// TODO: write the path C:\Users\ada as a raw string, no escaping
val path = ""
println(path)
} Show answer Hide answer
val path = """C:\Users\ada""" Nullability and the special types
8. Opt into null
Declare a String that may hold null and assign it null. Then declare one that may not hold null.
fun main() {
// TODO: declare a String? holding null, and a non-null String
val maybe = ""
val name = ""
println(maybe)
println(name)
} Show answer Hide answer
var maybe: String? = null
val name: String = "Ada" 9. Length or zero
Implement lengthOrZero so it returns the string’s length, or 0 when it’s null — in one expression.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun lengthOrZero() {
Assert.assertEquals("length of a present string", 2, lengthOrZero("hi"))
Assert.assertEquals("zero when null", 0, lengthOrZero(null))
}
}
//sampleStart
fun lengthOrZero(maybe: String?): Int =
0 // TODO: maybe's length, or 0 when it's null
//sampleEnd Show answer Hide answer
fun lengthOrZero(maybe: String?) = maybe?.length ?: 0 10. A function that never returns
Write fail(message: String) that always throws IllegalStateException. What’s its return type?
// TODO: make fail always throw IllegalStateException. What's its return type?
fun fail(message: String) {
println(message)
}
fun main() {
fail("nope")
} Show answer Hide answer
fun fail(message: String): Nothing = throw IllegalStateException(message)Nothing — the type of an expression that never returns a value.
11. The void stand-in
A function prints a line and returns no meaningful value. What is its return type, and do you have to write it?
// TODO: write log(msg: String) that prints msg. What's its return type — and do you write it?
fun log(msg: String) {
// TODO: print msg
}
fun main() {
log("hello")
println("done")
} Show answer Hide answer
The return type is Unit, and you don’t write it — it’s the default when you omit the return type.
fun log(msg: String) {
println(msg)
} Going deeper: overflow, unsigned, and boxing
12. Silent overflow
Kotlin’s fixed-width integers wrap on overflow, exactly like Java. Make overflow() return whatever Int.MAX_VALUE + 1 evaluates to, and predict the sign before you run it.
fun main() {
// TODO: return Int.MAX_VALUE + 1 — what sign is it?
println(overflow())
}
fun overflow(): Int = 0 Show answer Hide answer
fun overflow(): Int = Int.MAX_VALUE + 1 // -2147483648No exception — it wraps around to the most negative Int. If a sum might exceed Int.MAX_VALUE, use Long or the checked Math.addExact.
13. Reinterpret the bits as unsigned
Implement asUnsigned so it returns the unsigned interpretation of an Int’s bit pattern — for -1, that’s 4294967295.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun asUnsigned() {
Assert.assertEquals(4294967295u, asUnsigned(-1))
Assert.assertEquals(0u, asUnsigned(0))
}
}
//sampleStart
fun asUnsigned(n: Int): UInt =
0u // TODO: reinterpret n's bits as an unsigned value
//sampleEnd Show answer Hide answer
fun asUnsigned(n: Int) = n.toUInt()toUInt() reinterprets the same 32 bits without sign, so -1 (all ones) becomes 4294967295.
14. Walk the alphabet
Char + Int gives a Char, but Char + Char doesn’t compile. Implement shift so shift('A', 1) is 'B'.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun shift() {
Assert.assertEquals('B', shift('A', 1))
Assert.assertEquals('a', shift('z', -25))
}
}
//sampleStart
fun shift(c: Char, n: Int): Char =
' ' // TODO: return the character n places along
//sampleEnd Show answer Hide answer
fun shift(c: Char, n: Int) = c + nChar + Int is defined and returns a Char; c.code would give you the number the other way.
15. Structural vs referential
Given two strings built differently but with the same contents, which comparison is true — a == b or a === b? Reveal to check your reasoning.
Show answer Hide answer
a == b is true (same contents — == calls equals), while a === b is false (different objects). And for boxed numbers, === on two Int? is now a compiler warning, precisely because the answer depends on the boxing cache.
Back to the lesson, In Kotlin, There Are No Primitives, or on to the next one: functions.
Comments