When is the else branch mandatory for an if in Kotlin, and when is it optional? Show an example of each.
answer
- Result used = expression = else required
- Result discarded = statement = else optional
- Block branch value = last expression
- return/throw branch has type Nothing
- Mandatory else makes if a total ternary
basics
~20 sIf you use the if's result (assign it, return it, pass it), you must include else so every path produces a value. If you ignore the result and just run side effects, else is optional.
solid answer
~50 sThe rule hinges on whether `if` is used as an **expression** or a **statement**. As an expression — when its result is assigned, returned, or passed as an argument — every execution path must yield a value, so `else` is **mandatory**. `val x = if (c) 1` does not compile because the false path would have no value. As a statement — when you discard the result and only run side effects — `else` is **optional**: `if (c) doThing()` is fine. The compiler decides which mode applies from context. A subtle case: in a function whose body is a single `if`, if the branches `return`/`throw` (type `Nothing`) the compiler can still verify all paths terminate, but if you assign the whole `if` to a variable you still need `else`. The mandatory-else rule is what makes `if` a safe ternary replacement: there is always a defined value.
code
kotlin · 10 linesfun statementMode(c: Boolean) {
if (c) println("hi") // OK, no else
}
fun expressionMode(c: Boolean): Int {
val v = if (c) 1 else 0 // else required
return v
}
// fun broken(c: Boolean): Int = if (c) 1 // does NOT compilego deeper
States that else is needed when assigning the if's result and optional for plain side-effect ifs.
Articulates the expression-vs-statement distinction and shows both cases with correct examples.
Explains Nothing-typed throw/return branches and how block branches resolve to their last expression.
Connects mandatory-else totality to type safety and the ternary-replacement design rationale.
## Expression mode vs statement mode Kotlin's `if` works in two modes, and the `else` requirement depends on the mode. ### Statement mode — else optional When the result is **not used**, `if` is a plain control-flow statement. You may omit `else`: ```kotlin if (user.isAdmin) grantAccess() // no else needed ``` Nothing consumes a value, so a missing branch simply does nothing. ### Expression mode — else mandatory When the result **is used** — assigned to a `val`/`var`, returned, or passed as an argument — `if` is an expression and **must** have `else`: ```kotlin val grade = if (score >= 60) "pass" else "fail" // else required ``` Without `else`, the false case would produce no value, so the type would be undefined. The compiler rejects: ```kotlin // val grade = if (score >= 60) "pass" // ERROR: 'if' must have both branches ``` ### Why this exists This is precisely what lets `if` replace the ternary safely: an assigned `if` is **total** — it always yields a value. ### Edge case: Nothing-typed branches A branch that `return`s or `throw`s has type **Nothing** (the type with no values, a subtype of every type). The compiler treats such a branch as non-returning. So this single-expression function is valid: ```kotlin fun describe(n: Int): String = if (n > 0) "positive" else throw IllegalArgumentException("non-positive") ``` Here `else` is still present; the `throw` branch contributes `Nothing`, and the overall type narrows to `String`. ### Block branches Branches can be blocks; the **last expression** of a block is its value: ```kotlin val n = if (flag) { log("taking true path") 42 // value of the block } else { 0 } ``` ### Summary table - Result used (expression) → `else` required. - Result discarded (statement) → `else` optional.
- Why does a branch that throws still let the expression compile with a single resolved type?throw produces type Nothing, a subtype of every type. The expression type becomes the other branch's type, since Nothing imposes no upper bound.
- What is the value of a block branch?The value of its last expression. Earlier lines run as side effects; the final expression determines the branch's result.
saying these in an interview costs you the question
- Saying else is always required for every if
- Saying else is never required
- Not connecting the rule to expression vs statement usage
- Believing a throw branch needs a fake return value
- Thinking a block branch returns its first line