Checkpoint: Kotlin Basics
This checkpoint is a hands-on review that ties together everything from the basics track — control flow, ranges, strings, arrays, type checks, visibility, destructuring, and lateinit/lazy — into one build challenge and a short quiz.
Learn Checkpoint: Kotlin Basics in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Work through it to confirm the foundations are solid before stepping up to higher-order functions.
What This Checkpoint Covers
1️⃣ Recap at a Glance
Before the challenge, here's a compact map of the eight skills you've built. Each links back to its full lesson if you want a refresher.
2️⃣ Warm-Up
A short mixed example to shake off the rust — it touches control flow, ranges, strings, and destructuring all at once. Trace it before you run it.
3️⃣ Build Challenge: Student Report
Now combine the skills. Process a list of students with destructuring , classify each score with a range inside when , format output with string templates , and finish with a computed average. The starter below has the data and the spec — write the body, then reveal the solution to check yourself.
One clean way to write it, using a small helper function for the grading logic:
⏱ Timed Quiz
That if in Kotlin is an expression : it returns a value, so it replaces the ternary operator other languages have. The else is required when used this way.
1 until 5 visits 1, 2, 3, 4 (excludes the top), while 1..5 visits 1, 2, 3, 4, 5 (includes both ends). until is the half-open range.
Arrays use the default object representation, so you see something like [Ljava.lang.Integer;@... . Use .toList() or .joinToString() to print the elements.
Because of a smart cast : once the is check passes, the compiler treats x as a String inside that block, so no explicit as is needed.
By position . The first variable receives component1() (the first property) no matter what you name it, so the order must match the class's properties.
lateinit var is a non-null var you assign manually before use. by lazy is a val computed automatically on first access and cached. Use lateinit for injected values, lazy for deferred computation.
Practice quiz
What does val max = if (a > b) a else b demonstrate about Kotlin's if?
- if is only a statement
- if is an expression that returns a value
- if requires curly braces
- if cannot have an else
Answer: if is an expression that returns a value. In Kotlin if is an expression that returns a value, so it replaces the ternary operator and the else is required.
Which numbers does for (i in 1 until 5) iterate over?
- 1, 2, 3, 4, 5
- 1, 2, 3, 4
- 0, 1, 2, 3, 4
- 2, 3, 4, 5
Answer: 1, 2, 3, 4. until is a half-open range, so 1 until 5 visits 1, 2, 3, 4 and excludes the top endpoint.
How do you check whether a value is inside the range 1..10?
- x within 1..10
- 1..10 has x
- x in 1..10
- x between 1, 10
Answer: x in 1..10. The in operator tests membership: x in 1..10 is true when x is between 1 and 10 inclusive.
Why does println(arrayOf(1, 2, 3)) print a cryptic value?
- Arrays cannot be printed
- It uses the default object representation, not the elements
- The array is empty
- Integers are not printable
Answer: It uses the default object representation, not the elements. Arrays use the default Object toString, so you must use joinToString() or toList() to print the elements.
After if (x is String), why can you call x.length without a cast?
- String has no length
- Kotlin smart-casts x to String inside the block
- You still need an explicit as cast
- is always returns a String
Answer: Kotlin smart-casts x to String inside the block. Once the is check passes, the compiler smart-casts x to String within that scope, so no explicit cast is needed.
In val (name, age) = user, how are the variables matched?
- By name
- By type
- By position
- Alphabetically
Answer: By position. Destructuring is positional: the first variable gets component1(), the second component2(), regardless of name.
Which visibility modifier limits a declaration to the same module?
- private
- protected
- internal
- public
Answer: internal. internal restricts visibility to the same module; private is file/class scope, protected adds subclasses, public is everywhere.
What is the key difference between lateinit var and by lazy?
- They are the same
- lateinit is a var you assign manually; by lazy is a val computed on first access
- lazy must be a var
- lateinit caches its value automatically
Answer: lateinit is a var you assign manually; by lazy is a val computed on first access. lateinit var is assigned manually before use, while by lazy is a val computed automatically on first read and cached.
How do you get a fractional average from two Ints, total and size?
- total / size
- total.toDouble() / size
- total % size
- Double(total / size)
Answer: total.toDouble() / size. Int / Int does integer division; convert first with total.toDouble() / size to force floating-point division.
Which expression produces the list [0, 2, 4, 6]?
- (0..6 step 2).toList()
- (0..6).toList()
- (0 until 6).toList()
- (0..6 step 3).toList()
Answer: (0..6 step 2).toList(). A range with step 2 from 0..6 yields 0, 2, 4, 6, and toList() materializes it.