skip to content

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%

answer

  1. = single expression => its value is the return; type inferable
  2. {} block => use return; non-Unit type must be explicit
  3. if/when/try expressions collapse blocks into one expression
  4. public API: declare return type even with =
  5. expression-body if needs else

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.

solid answer

~50 s

An **expression-body** function defines its body as a single expression after `=`: `fun double(x: Int) = x * 2`. The function's return value **is** that expression, and the **return type can be inferred** from it, so you can omit the `: Type`. A **block-body** function uses `{ ... }` and must use the `return` keyword to produce a non-`Unit` value; if it returns anything other than `Unit` its return type **must be declared explicitly** (no inference for block bodies). You can still write the type on an expression-body function for documentation or to widen/narrow it. Because `if`, `when`, and `try` are expressions, many block functions collapse into a single expression body — e.g. `fun sign(n: Int) = when { n > 0 -> 1; n < 0 -> -1; else -> 0 }`. For public API, explicit return types are recommended even on expression bodies so the signature is stable and doesn't silently change with the implementation.

code

kotlin · 14 lines
kotlin
// expression body, inferred Int
fun square(x: Int) = x * x

// expression body wrapping a when, explicit type for clarity
fun describe(x: Int): String = when {
    x == 0 -> "zero"
    x > 0  -> "positive"
    else   -> "negative"
}

// block body: must declare type and use return
fun cube(x: Int): Int {
    return x * x * x
}

go deeper

for a junior

Recognizes fun f() = expr as a shorthand and that {} bodies use return.

for a middle

Knows expression bodies infer the return type while block bodies require an explicit non-Unit type.

for a senior

Explains the public-API inference pitfall and how if/when/try expressions enable concise single-expression functions.

for a principal

Sets team conventions (explicit types on public surface), reasons about binary compatibility and inference's impact on API evolution.

## Two function body forms **Block body** uses braces and `return`: ```kotlin fun double(x: Int): Int { return x * 2 } ``` **Expression body** uses `=` and a single expression — the expression's value is the return value: ```kotlin fun double(x: Int) = x * 2 ``` ## Return-type inference rules - **Expression body:** the return type **can be inferred** from the expression, so `: Type` is optional. - **Block body:** the return type is **not inferred** (except `Unit`); if the function returns a non-`Unit` value you **must** declare the type explicitly, and use `return`. ```kotlin fun f() = 1 // inferred Int (expression body) fun g(): Int { return 1 } // type required for block body ``` ## Expression-oriented constructs make bodies shrink Since `if`/`when`/`try` are expressions, a whole branching function becomes one expression: ```kotlin fun grade(s: Int): String = when { s >= 90 -> "A" s >= 80 -> "B" else -> "C" } ``` ## Mind the inference pitfalls - Omitting the type ties your public signature to the implementation; a refactor can silently change the inferred type and break callers/binary compatibility. **Declare explicit return types on public API**, even with `=`. - An expression body that ends in a side-effecting call typed `Unit` returns `Unit`: `fun log(m: String) = println(m)`. - `= Unit`-typed function vs a block `{}` are equivalent for side-effect-only functions. ## Single-expression with `if` requiring else Because the expression must yield a value, an `if` here needs `else`: ```kotlin fun abs(n: Int) = if (n < 0) -n else n // else mandatory ``` ## Key APIs/keywords `=` expression body, block body `{}` + `return`, return-type inference, `Unit`, public-API explicit types.

  • Why declare an explicit return type on a public expression-body function?
    To pin the public signature: relying on inference means a refactor could change the inferred type and silently break source/binary compatibility for callers.
  • Can a block-body function infer a non-Unit return type?
    No. Block bodies only infer Unit; any other return type must be declared explicitly, and the value produced via the `return` keyword.

Expression body is a one-line recipe card (= the dish); block body is a numbered procedure that must say 'serve this' (return).

saying these in an interview costs you the question

  • Claiming block-body functions infer their return type
  • Using `return` inside an expression body (`= return ...`)
  • Forgetting the `else` in an expression-body `if`
  • Never declaring return types on public API and relying on inference
  • Thinking `=` body and `{}` body are interchangeable syntactically (block needs return)

context