skip to content

Statements vs Expressions

In Kotlin if, when, and try hand back a value, while loops and assignments do not, and Unit fills the 'no meaningful result' slot. Interviewers ask because expression-bodied functions and value-returning when are the difference between idiomatic Kotlin and transliterated Java.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

6

In Kotlin, why is there no ternary operator (cond ? a : b), and how do you write the equivalent?

level: juniorimportance: must knowfreq 70%

answer

  1. if returns a value -> no ternary needed
  2. expression use => else is mandatory
  3. branch value = last expression in block
  4. ?: is Elvis (null fallback), not a ternary
  5. no else => statement, type Unit

basics

~10 s

In Kotlin an if returns a value, so you just write val x = if (cond) a else b. Because if already gives a result, a separate ?: ternary operator is not needed.

solid answer

~40 s

Kotlin drops the C-style ternary `cond ? a : b` because `if` is an expression: it evaluates to the value of the chosen branch, so `val max = if (a > b) a else b` does the job. When `if` is used as an expression (its result is assigned, returned, or passed), the `else` branch is mandatory so the compiler can guarantee a value exists in every case. Each branch's value is the value of its last expression; with `{}` blocks the last statement in the block is the result. `if` without `else` is allowed only in statement position (its type is then `Unit`). Don't confuse this with the Elvis operator `?:`, which is for null fallback (`a ?: b`), not general conditionals.

code

kotlin · 11 lines
kotlin
// Java: int max = a > b ? a : b;
val max = if (a > b) a else b

// block branches: value is the last expression
val grade = if (score >= 90) {
    "A"
} else if (score >= 80) {
    "B"
} else {
    "C"
}

go deeper

for a junior

Knows if returns a value and writes val x = if (c) a else b instead of looking for a ternary.

for a middle

Explains why else is mandatory in expression position and that a branch's value is its last expression.

for a senior

Distinguishes statement vs expression position, the Unit-typed no-else form, and separates Elvis from conditionals.

for a principal

Frames it as a language-design choice (fewer constructs, expression-oriented) and can reason about type inference of the common supertype of branches.

## Statement vs expression An **expression** produces a value (it can sit on the right of `=`, be returned, or be passed as an argument). A **statement** performs an action but yields no usable value. In Kotlin many constructs that are *statements* in Java/C are *expressions*. ## `if` is an expression In Kotlin `if` evaluates to the value of whichever branch is taken: ```kotlin val max = if (a > b) a else b ``` Because `if` already yields a value, Kotlin deliberately has **no ternary operator** `?:`-as-`cond ? a : b`. The single-line form reads as well as a ternary. ## The `else` is mandatory in expression position When the result of `if` is used (assigned/returned/passed), you **must** provide `else`. Without it the compiler can't prove a value is produced when the condition is false: ```kotlin val x = if (cond) 1 // ERROR: 'if' must have both branches if used as an expression val y = if (cond) 1 else 0 // OK ``` Used purely for side effects (statement position), `else` is optional and the `if` has type `Unit`. ## Branch value = last expression A branch can be a block; its value is the **last expression** in the block: ```kotlin val label = if (score >= 50) { log("pass") "PASS" // this is the branch's value } else "FAIL" ``` ## Don't confuse with Elvis `?:` Kotlin *does* have `?:`, the **Elvis operator**, but it only does null fallback: `name ?: "anon"` returns `name` if non-null else `"anon"`. It is not a general conditional. ## Key APIs/keywords `if`/`else` as expression, `Unit`, Elvis `?:` (null fallback only).

  • What is the type of `if (cond) doX()` when there is no else?
    `Unit` — without an else it is used as a statement for side effects, and its value type is Unit.
  • Is `a ?: b` the same as `if (a != null) a else b`?
    Effectively yes for the null case: Elvis returns the left if non-null, else the right. But `a` is evaluated once, and it's null-specific, not a general boolean condition.

Asking for a ternary in Kotlin is like asking for a special spoon when the fork already scoops fine.

saying these in an interview costs you the question

  • Claiming Kotlin has a `?:` ternary that takes a boolean condition
  • Saying `else` is optional even when the if's value is assigned
  • Confusing Elvis `?:` with a general conditional
  • Thinking `if` is only a statement like in Java

context

open as a page

What is `Unit` in Kotlin, how does it differ from Java's `void`, and where does it appear?

level: middleimportance: must knowfreq 60%

basics

~20 s

Unit is Kotlin's 'no meaningful result' type. A function that doesn't return anything useful returns Unit. Unlike Java's void keyword, Unit is a real type with a single value, so it can be used in generics and lambdas.

open as a page

How does `when` behave as an expression, and what exhaustiveness rules apply to it?

level: middleimportance: must knowfreq 65%

basics

~20 s

when can return a value, so you can assign its result. When used as an expression it must cover every possible case — usually by adding an else branch, or covering all options of an enum or sealed type.

open as a page

Why can't you write `val b = (a = 5)` or use an assignment/loop as a value in Kotlin?

level: middleimportance: should knowfreq 35%

basics

~20 s

In Kotlin, assignments and loops are statements, not expressions, so they don't produce a value you can store. That's why val b = (a = 5) doesn't compile and you can't use a for/while loop on the right side of =.

open as a page

What is the difference between an expression-body function (`fun f() = ...`) and a block-body function, and when does return-type inference apply?

level: seniorimportance: should knowfreq 50%

basics

~20 s

An expression-body function uses = and a single expression as its whole body, and its return type can be inferred. A block-body function uses { } and must use return for any non-Unit result, with the return type usually written explicitly.

open as a page

Can a `try`/`catch` block be used as an expression in Kotlin? How is its value determined?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Yes. A try/catch can return a value. If the try block succeeds, its last expression is the result; if it throws and a catch handles it, that catch block's last expression is the result. A finally block never affects the value.

open as a page