Explain Kotlin's when as an expression: its forms, exhaustiveness rules, and how it replaces switch.
answer
- Two forms: with subject vs subject-less (if/else-if)
- Conditions: values, commas, in ranges, is types
- Expression when must be exhaustive (or else)
- Sealed/enum: compiler checks exhaustiveness, no else needed
- Top-down, no fall-through, no break
basics
~10 swhen is Kotlin's flexible replacement for switch. It can return a value, match ranges or types, and needs to cover every case (be exhaustive) when used as an expression.
solid answer
~40 s`when` is an **expression** (and also usable as a statement) that generalizes `switch`. It has two forms: with a subject — `when (x) { ... }` — and without one, where each branch is a boolean condition (`when { a > 0 -> ... }`), effectively an if/else-if chain. Branch conditions can be literals, comma-separated values, `in` range/collection checks, and `is` type checks (which trigger smart casts). `else` is the catch-all. When `when` is used as an **expression**, it must be **exhaustive**: cover all cases or include `else`. For sealed classes and enums the compiler can verify exhaustiveness without `else`, and a non-exhaustive `when` over them is now a compile error. Branches are evaluated **top-down**, and there is no fall-through, so no `break` is needed.
code
kotlin · 6 linesfun classify(x: Any): String = when (x) {
in 1..9 -> "single digit"
is String -> "len=${x.length}" // smart cast to String
null -> "null"
else -> "other"
}go deeper
Knows when replaces switch and can return a value; uses else.
Explains both forms, in/is conditions, and that expression-form when must be exhaustive.
Leverages compiler-checked exhaustiveness over sealed/enum types and avoids a redundant else to keep checks active.
Uses sealed hierarchies + exhaustive when as a domain-modeling tool so the compiler enforces total handling across the codebase.
## when replaces switch `when` is Kotlin's multi-way branch. Unlike Java's `switch`, it is an **expression** (returns a value), supports rich conditions, and has **no fall-through** (no `break` needed). ### Form 1 — with a subject ```kotlin val label = when (code) { 0 -> "zero" 1, 2, 3 -> "small" // comma = multiple matches in 4..9 -> "mid" // range check via in is String -> "text" // type check via is (smart-casts code) else -> "other" } ``` Branch conditions can be: constant values, comma-separated alternatives, `in`/`!in` for ranges and collections, and `is`/`!is` for type checks (with smart casts inside the branch). ### Form 2 — without a subject Omit the subject and each branch becomes a boolean condition — an if/else-if chain: ```kotlin val sign = when { n > 0 -> "+" n < 0 -> "-" else -> "0" } ``` ## Exhaustiveness When used as an **expression** (its value is assigned/returned), `when` must be **exhaustive** — every possible input is handled, or an `else` is present. - For **enums** and **sealed** hierarchies the compiler knows all cases, so listing them all makes `else` unnecessary — and it will warn/error if you add a case later and forget to handle it. - A non-exhaustive `when` expression over a sealed type or enum is a **compile error**. ```kotlin sealed interface Shape class Circle : Shape class Square : Shape fun area(s: Shape): String = when (s) { // no else needed is Circle -> "pi r^2" is Square -> "a^2" } ``` Used as a pure **statement**, exhaustiveness is not enforced (you may omit `else`). ## Evaluation semantics - Branches are checked **top to bottom**; the first match wins. - There is **no fall-through**, so no `break`. - A subject can be captured: `when (val r = compute()) { ... }`. ## Why this matters Enforced exhaustiveness over sealed types turns "forgot a case" into a compile-time error, which is a core reason teams model domains with sealed hierarchies.
- Why prefer a sealed class with when over an enum-plus-else?With a sealed class, an exhaustive when has no else, so adding a new subtype forces a compile error in every when that didn't handle it — the compiler finds all the spots you must update.
- Does when fall through like a C switch?No. The first matching branch runs and execution leaves the when; there is no fall-through and no break keyword.
saying these in an interview costs you the question
- Adding break inside when branches
- Putting a catch-all else on a sealed when, defeating exhaustiveness checks
- Not knowing the subject-less form exists
- Thinking when only matches constants like switch
- Believing exhaustiveness is checked even for statement-form when