When does an anonymous function's block body return Unit unexpectedly, and how do explicit vs inferred return types behave for block versus expression bodies?
answer
- block body default = Unit
- expression body = inferred type
- anon fun block != lambda last-expr
- need explicit return in block body
- fun(x)=x*2 is the safe rewrite
basics
~20 sAn anonymous function with a block body { } returns Unit unless you declare a return type or use a return statement. An expression body (= ...) infers its type from the expression. So a block body without an explicit type can surprise you by returning Unit.
solid answer
~50 sFor an **expression-body** anonymous function (fun(x: Int) = x * 2) the return type is **inferred** from the expression, exactly like a regular expression-body function. For a **block-body** anonymous function (fun(x: Int) { ... }) the return type is **Unit** unless you declare it explicitly (fun(x: Int): Int { ... }) and actually return a value. Unlike a lambda — whose result is the value of its last expression — a block-bodied anonymous function does NOT implicitly return its last expression; you must use return. This mirrors normal fun declarations and is a common source of confusion when converting a lambda { it * 2 } to fun(it: Int) { it * 2 }, which silently becomes () -> Unit. The fix is either an expression body fun(x: Int) = x * 2 or an explicit return: fun(x: Int): Int { return x * 2 }.
go deeper
Knows expression body infers a type; may not anticipate the block-body Unit trap.
Explains the Unit default for block bodies and contrasts it with lambda last-expression semantics.
Predicts where a silent Unit will compile vs error and refactors lambdas to anonymous functions safely.
Anticipates these traps in API design and code review, steering toward forms that fail loudly.
## Two body forms, two rules Anonymous functions follow the **same return-type rules as named functions**, which differ from lambdas. ### Expression body — type is inferred ```kotlin val f = fun(x: Int) = x * 2 // inferred return type Int -> type is (Int) -> Int ``` The `= expression` form infers the return type from the expression. You may still annotate it: `fun(x: Int): Int = x * 2`. ### Block body — defaults to Unit ```kotlin val g = fun(x: Int) { x * 2 } // block body, NO return -> return type Unit -> (Int) -> Unit ``` A block body `{ ... }` does **not** treat its last expression as the result. Without an explicit `return`, the function returns `Unit`. `x * 2` here is a discarded expression. To return a value you must: ```kotlin val h = fun(x: Int): Int { return x * 2 } // (Int) -> Int ``` ## Contrast with lambdas A lambda's value **is** its last expression: ```kotlin val lam: (Int) -> Int = { x -> x * 2 } // last expression x*2 is the result ``` So the dangerous refactor is mechanically turning a lambda into a block-body anonymous function: ```kotlin // before list.map { it * 2 } // WRONG: becomes (Int) -> Unit, won't satisfy map's (Int) -> R where R = Unit -> List<Unit> list.map(fun(it: Int) { it * 2 }) // RIGHT list.map(fun(it: Int) = it * 2) list.map(fun(it: Int): Int { return it * 2 }) ``` ## Why this matters The compiler will usually catch the mismatch when the expected type requires a non-Unit result, producing a type error. But in positions that accept `(T) -> Unit` (e.g. `forEach`), the silent `Unit` result compiles fine and your computed value is quietly thrown away. ## Recall - Expression body `= e` -> inferred return type. - Block body `{ }` -> `Unit` unless you `return` a value (and usually declare the type). - Lambda -> last expression is the result; anonymous function block body -> it is not.
- Why does fun(it: Int) { it * 2 } compile but produce the wrong type?Block bodies return Unit unless you return a value; it * 2 is evaluated and discarded, so the type is (Int) -> Unit.
- Does declaring : Int on a block body without a return statement compile?No. If you declare a non-Unit return type you must return a value on all paths, or the compiler errors that a return is expected.
saying these in an interview costs you the question
- Claiming a block-body anonymous function returns its last expression like a lambda
- Thinking expression and block bodies follow the same return rule
- Not realizing a silent Unit can compile in forEach-style positions
- Believing the return type is always required to be declared