Control Flow & Destructuring

Kotlin Fundamentals — Control Flow & Destructuring
Kotlin Fundamentals
Course 1 · Chapter 7 · Control Flow & Destructuring

🔀 Control Flow & Destructuring

This chapter rounds out the fundamentals with Kotlin's expression-oriented control flow — where if and when produce values rather than just branching — plus ranges, loop syntax, and destructuring declarations, which unpack a value into several variables in one line.

🎛️ when — Kotlin's Souped-Up switch

val day = 3 val dayName = when (day) { 1 -> "Monday" 2 -> "Tuesday" 3 -> "Wednesday" 6, 7 -> "Weekend" else -> "Unknown day" } println(dayName) // Wednesday

when is a direct upgrade over Java/JavaScript's switch: no break is needed (there's no fallthrough to guard against), a single branch can match multiple values (6, 7 ->), and — critically — when is an expression, meaning it produces a value that can be assigned directly, as shown above.

// when without an argument — replaces a long if/else-if chain val score = 85 val grade = when { score >= 90 -> "A" score >= 80 -> "B" score >= 70 -> "C" else -> "F" } println(grade) // B

Without a subject in parentheses, each branch is a boolean condition evaluated top to bottom — the first one that's true wins. This form directly replaces a chain of if / else if / else if / else, and reads more clearly once there are more than two or three conditions.

switch vs when

Java/JavaScript switchKotlin when
FallthroughFalls through without breakNever falls through
Multiple values, one branchcase 6: case 7: ...6, 7 -> ...
Produces a value?No — statement onlyYes — can be an expression
Condition-only formNot available (need if/else-if)when { cond -> ... }

🔢 Ranges

for (i in 1..5) print("$i ") // 1 2 3 4 5 println() for (i in 1 until 5) print("$i ") // 1 2 3 4 — excludes 5 println() for (i in 5 downTo 1) print("$i ") // 5 4 3 2 1 println() for (i in 1..10 step 2) print("$i ") // 1 3 5 7 9

1..5 creates an inclusive range (both ends included). until makes the upper bound exclusive — the direct equivalent of a classic for (int i = 0; i < 5; i++) loop. downTo counts backward, and step changes the increment. Ranges aren't just for loops either — if (age in 13..19) println("Teenager") reads naturally as a membership check.

🔁 Loops

val fruits = listOf("apple", "banana", "cherry") // for-each — the most common loop by far for (fruit in fruits) { println(fruit) } // index + value together, via withIndex() for ((index, fruit) in fruits.withIndex()) { println("$index: $fruit") } // while — identical to Java/JavaScript var countdown = 3 while (countdown > 0) { println(countdown) countdown-- }

The for (item in collection) form is Kotlin's only for syntax — there's no classic C-style for (int i = 0; i < n; i++) loop at all. Combined with ranges, the same job is done with for (i in 0 until n), and combined with withIndex(), index-and-value iteration reads naturally without manual index bookkeeping.

📦 Destructuring Declarations

A value can be "unpacked" into several variables in one line, if the type supports it — data classes support this automatically, based on constructor property order:

data class Point(val x: Int, val y: Int) val point = Point(3, 7) val (x, y) = point println("x=$x, y=$y") // x=3, y=7

The earlier withIndex() loop was already destructuring in action: (index, fruit) unpacks each pair the loop produces. Map iteration destructures the same way:

val ages = mapOf("Alice" to 30, "Bob" to 25) for ((name, age) in ages) { println("$name is $age") } // Alice is 30 // Bob is 25

Ignoring a Component: _

An underscore skips a component you don't need: val (x, _) = point unpacks only x, discarding y without needing to name an unused variable.

Order Matters, Not Names

Destructuring is positional — it maps to a data class's constructor properties in declared order, regardless of what you name the variables on the left-hand side.

⚠ Only Works on Destructuring-Capable Types

Destructuring relies on the type providing component1(), component2(), etc. — data classes generate these automatically, and Pair/Map.Entry provide them too, which is why for ((k, v) in map) works. A plain (non-data) class does not support this syntax unless those component functions are written manually.

💻 Coding Challenges

Challenge 1: when as an Expression

Write a function seasonFor(month: Int): String that uses a when expression (with grouped values, e.g. 12, 1, 2 -> "Winter") to return the season name for a given month number (1-12), directly returning the when result with no explicit return statement.

Goal: Use when as an expression, including grouped-value branches.

→ Solution

Challenge 2: Ranges and Loops

Using a range-based for loop, print every odd number from 1 to 20 using step. Then, given val colors = listOf("red", "green", "blue"), use withIndex() to print each color with its index in the format 0: red.

Goal: Combine range step with index-and-value loop iteration.

→ Solution

Challenge 3: Destructuring a Map

Create a data class Product(val name: String, val price: Double), destructure an instance into name and price variables and print them. Then create a Map<String, Double> of three product names to prices, and use a destructuring for-loop to print each as "name: $price".

Goal: Practice destructuring both a data class instance and a Map in a loop.

→ Solution

💡 Course 1 Is Nearly Complete

This chapter closes out the core language fundamentals — types, functions, null safety, classes, collections, and control flow. The final chapter of this course covers extension functions and object declarations, two features that round out how idiomatic Kotlin code is actually structured day to day.

🎯 What's Next

Next chapter: Extension Functions & Object Declarations — extending existing classes, singletons, and object expressions.