Control Flow & Destructuring
🔀 Control Flow & Destructuring
🎛️ when — Kotlin's Souped-Up switch
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.
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 switch | Kotlin when | |
|---|---|---|
| Fallthrough | Falls through without break | Never falls through |
| Multiple values, one branch | case 6: case 7: ... | 6, 7 -> ... |
| Produces a value? | No — statement only | Yes — can be an expression |
| Condition-only form | Not available (need if/else-if) | when { cond -> ... } |
🔢 Ranges
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
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:
The earlier withIndex() loop was already destructuring in action: (index, fruit) unpacks each pair the loop produces. Map iteration destructures the same way:
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.
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.
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.
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.
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.