Phase 1 · FoundationsModule 5~32 min read

Control Flow

Make decisions with if and the powerful when expression, and loop over ranges and collections.

What you'll learn

Real programs make decisions. Kotlin's control flow has a twist that makes it especially expressive: if and when are expressions — they return values — so you write less and say more.

By the end you'll be able to:

  • Use if as both a statement and a value-returning expression
  • Harness the powerful when expression
  • Match on values, ranges, types, and arbitrary conditions
  • Loop with for and while

if as an expression

In Kotlin, if doesn't just choose which code to run — it returns a value. That means you can assign its result directly to a variable. A happy consequence: Kotlin has no separate ternary operator, because if/else already fills that role concisely:

If.kt
val score = 82

// 'if' is an EXPRESSION — it returns a value
val grade = if (score >= 90) "A"
            else if (score >= 80) "B"
            else "F"
println(grade)          // B

// so Kotlin has no separate ternary — 'if' IS the ternary
val max = if (5 > 3) 5 else 3
println(max)            // 5

The when expression

when is Kotlin's supercharged replacement for the switch statement — and it's an expression too. It can match against literal values, ranges, types (with smart casts), and even arbitrary conditions when used without an argument:

What when can match

1 -> ...

match a literal value

in 4..5 -> ...

match a range

is String -> ...

match a type (with smart cast)

temp > 30 -> ...

match any condition (no argument)

When.kt
val day = 3

val name = when (day) {           // 'when' as an expression
    1 -> "Monday"
    2 -> "Tuesday"
    3 -> "Wednesday"
    in 4..5 -> "Later in the week"
    else -> "Weekend"
}
println(name)           // Wednesday

Matching on types pairs beautifully with smart casts (Module 4):

WhenType.kt
fun describe(x: Any) = when (x) {
    is Int -> "an int: ${x}"
    is String -> "a string of length ${x.length}"
    else -> "something else"
}

println(describe(42))
println(describe("hi"))

And with no argument, each branch is a boolean condition — a clean if/else-if chain:

WhenCond.kt
val temp = 30

val advice = when {               // no argument — like an if/else chain
    temp > 30 -> "Too hot"
    temp < 10 -> "Too cold"
    else -> "Just right"
}
println(advice)         // Just right

when must be exhaustive as an expression

When you use when to return a value, it must cover every case — usually with an else. This compiler check means you can never forget a case, which becomes a superpower with sealed classes (Module 18).

Loops

Kotlin's for is a "for each" loop — it iterates over ranges, collections, or anything iterable. There's no C-style index loop; you use ranges instead. while and do-while work as you'd expect:

Loops.kt
for (i in 1..3) {
    println("Count $i")
}

for (fruit in listOf("apple", "banana")) {   // for-each over a collection
    println(fruit)
}

var n = 3
while (n > 0) {
    print(n)
    n--
}

Tip

Need the index while looping a collection? Use for ((index, value) in list.withIndex()) — the Kotlin equivalent of Python's enumerate.

Recap & quick check

Key takeaways

  • if is an expression that returns a value — so Kotlin has no separate ternary operator.
  • when is a powerful switch that's also an expression.
  • when can match values, ranges (in 4..5), types (is String, with smart cast), or conditions (no argument).
  • As a value-returning expression, when must be exhaustive (usually via else).
  • for is a for-each over ranges/collections; use withIndex() for the index.

Quick check

1. Why does Kotlin have no ternary operator (?:)... for conditionals?

2. What is 'when' most like from other languages?

3. How can a 'when' branch match a range?

4. When used as an expression, a 'when' must be…

5. How does Kotlin's for loop work?

Nicely done. Next up: Module 6 — Functions, where you'll package logic into reusable pieces.