if, when and expressions that return values
Every program makes decisions. Kotlin's tools for that — if and when — carry one idea that
distinguishes the language from most others: they are expressions, meaning they produce a
value, not just perform an action. Once that clicks, a lot of Kotlin code gets shorter and safer.
if as an expression
You already know if as a statement:
val hour = 20
if (hour < 12) {
println("Good morning")
} else {
println("Good evening")
}
But in Kotlin, if also returns a value, so you can assign its result directly:
val greeting = if (hour < 12) "Good morning" else "Good evening"
println(greeting) // Good evening
The if is the value. This replaces the "ternary operator" (condition ? a : b) that other
languages have — Kotlin does not have a ternary, because it does not need one; if/else already
does the job and reads more clearly.
When a branch has several lines, the last expression in the block is its value:
val price = 250
val label = if (price > 200) {
val tier = "premium"
"This is a $tier seat" // this last line is the branch's value
} else {
"This is a regular seat"
}
One rule to remember: when you use if as an expression, the else is mandatory. Without it,
what would the value be when the condition is false? The compiler will not let you leave that
undefined.
when — the tool switch wishes it were
For more than two branches, when is Kotlin's answer, and it is far more capable than a Java
switch:
val rating = 4
val label = when (rating) {
5 -> "Excellent"
4 -> "Good"
3 -> "Average"
else -> "Poor"
}
println(label) // Good
Like if, when is an expression — it returns a value, assigned here to label. No break
statements (a switch classic footgun where forgetting one causes "fall-through" bugs); each branch
is self-contained.
when does much more than match single values:
val n = 42
val description = when {
n < 0 -> "negative"
n == 0 -> "zero"
n < 10 -> "small"
n < 100 -> "medium"
else -> "large"
}
println(description) // medium
With no argument after when, each branch is a boolean condition, checked top to bottom — this
form replaces a long if / else if / else if chain and reads far better.
You can also match multiple values, ranges, and types in one branch:
val day = 6
val kind = when (day) {
1, 2, 3, 4, 5 -> "weekday" // multiple values
6, 7 -> "weekend"
else -> "invalid"
}
val score = 75
val grade = when (score) {
in 90..100 -> "A" // a range
in 70..89 -> "B" // 70 to 89 inclusive
in 50..69 -> "C"
else -> "F"
}
println(grade) // B
in 70..89 uses a range (the next lesson's topic) and reads almost like English. Matching on
type with is — is String -> ... — is where when becomes genuinely powerful, and the
sealed-classes lesson builds an entire pattern on it.
The safety benefit: exhaustiveness
Here is why "expression" matters beyond brevity. When when is used as an expression, the compiler
requires it to cover every case — that is what the else is doing. You cannot accidentally
forget a branch and have the value be undefined; the compiler refuses:
val label: String = when (rating) {
5 -> "Excellent"
4 -> "Good"
// error: 'when' expression must be exhaustive, add an 'else' branch
}
This turns "I forgot to handle a case" from a runtime surprise into a compile-time error. With
sealed classes and enums, Kotlin gets even stricter and can check you have handled every possible
value without needing else at all — one of the language's best safety features, covered in the
classes module.
if versus when — which to use
- Two outcomes, one condition:
if/else. - Three or more branches, or matching one value against many:
when. - A chain of unrelated boolean conditions:
whenwith no argument (cleaner thanif/else if/else).
Both are expressions, so prefer assigning their result over reassigning a var inside branches.
This:
val label = when (rating) { 5 -> "Excellent"; 4 -> "Good"; else -> "Poor" }
is better than declaring var label and setting it inside each branch — it is a val, it cannot be
left unset, and the intent is obvious. This is the val-by-default habit and the expression habit
reinforcing each other.
Check your work
What makes if special in Kotlin. It is an expression — it produces a value you can assign.
Why Kotlin has no ternary operator. if/else as an expression already does the job, more
readably.
What a multi-line branch returns. Its last expression.
Why else is mandatory for an if expression. Otherwise the value would be undefined when the
condition is false.
What when improves over a Java switch. It is an expression, needs no break (no
fall-through bugs), and matches values, ranges and types.
What when with no argument does. Treats each branch as a boolean condition, top to bottom —
replacing an if/else if chain.
What exhaustiveness means, and why it is valuable. An expression when must cover every case,
turning a forgotten branch into a compile-time error.
When enums/sealed classes make else unnecessary. The compiler knows every possible value and
checks you handled them all.
The habit these reinforce. Assign the expression's result to a val rather than reassigning a
var in branches.
Practice
- Write an
ifexpression that assigns a greeting from the hour, and print it for two hours. - Remove the
elsefrom that expression and read the compiler error. - Write a
whenthat maps a rating 1–5 to a label, as an expression assigned to aval. - Write a
whenwith no argument that classifies a number as negative/zero/small/medium/large. - Use a range branch (
in 90..100) to turn a score into a grade. - Match multiple values in one branch (weekday/weekend from a day number).
- Write a
whenexpression assigned to aval, deliberately omit a needed branch, and read the exhaustiveness error. - Take an
if/else if/elsechain you have written before and rewrite it as an argument-lesswhen. Decide which reads better.
Official documentation
- Kotlin — Conditions and loops —
ifandwhenas expressions. - Kotlin — when expressions — Every form of
when, including ranges and types. - Kotlin — Coding conventions: when — Formatting guidance for these.
Next: loops and ranges — and why you will write fewer loops than you expect.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship