skip to content

Single-Expression Functions

When a function is one expression you can write it with = and let the return type be inferred. The habit to keep is annotating the return type on public API, where inference makes the contract implicit and fragile.

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

questions

5

What is a single-expression function in Kotlin, and how does its syntax differ from a regular block-body function?

level: juniorimportance: must knowfreq 70%

answer

  1. = instead of { }
  2. No return keyword
  3. Body is one expression
  4. if/when/try are expressions
  5. Enables return-type inference

basics

~20 s

It is a function whose body is a single expression written after an equals sign instead of curly braces. For example: fun square(x: Int) = x * x. The result of the expression is what the function returns.

solid answer

~40 s

A single-expression (expression-body) function replaces the block body { return ... } with = <expression>. The function's value is the expression itself, so no explicit return keyword is used. Example: fun square(x: Int): Int = x * x. With block bodies you write fun square(x: Int): Int { return x * x }. Because the right-hand side is an expression, the compiler can infer the return type, letting you drop the explicit type for simple cases: fun square(x: Int) = x * x infers Int. Expression bodies pair naturally with when, if, and elvis expressions, which are all expressions in Kotlin. Block-body functions cannot omit the return type (except those returning Unit) and require explicit return statements.

code

kotlin · 3 lines
kotlin
fun square(x: Int): Int = x * x
fun max(a: Int, b: Int) = if (a > b) a else b   // inferred Int
fun greeting(name: String?) = "Hello, " + (name ?: "guest")

go deeper

for a junior

Recognizes the = syntax, knows there is no return keyword and that the expression is the result.

for a middle

Knows if/when/try are expressions so non-trivial logic fits, and that the type can be inferred.

for a senior

Articulates readability trade-offs and when a block body is the better choice.

for a principal

Frames it as a style/idiom convention worth codifying in a team style guide and lint rules.

## What it is Kotlin lets you define a function in two body styles: - **Block body**: braces `{ ... }` containing statements, with explicit `return`. - **Expression body (single-expression function)**: an `=` followed by exactly one expression. The function evaluates that expression and returns its value. ```kotlin // Block body fun square(x: Int): Int { return x * x } // Expression body — same behavior fun square(x: Int): Int = x * x ``` ## Key mechanics - **No `return` keyword.** The expression after `=` *is* the return value. Writing `return` inside it is a syntax error in this form. - **It must be a single expression**, but in Kotlin many constructs are expressions: `if`, `when`, `try`, elvis `?:`, and function calls all produce values, so you can express quite complex logic. - **Return-type inference** is allowed: `fun square(x: Int) = x * x` — the compiler infers `Int`. This is only possible with expression bodies, never block bodies. ```kotlin fun describe(n: Int) = when { n < 0 -> "negative" n == 0 -> "zero" else -> "positive" } ``` ## Why use it It removes ceremony for small, pure functions and makes intent obvious: the function *is* its expression. It is idiomatic for accessors, mappers, and delegating one-liners. ## When NOT to use it If the body needs multiple statements, local variables across several lines, loops, or side effects, a block body is clearer. Forcing complex logic into one expression hurts readability.

  • Can you write 'return' inside a single-expression function body?
    No. The expression after = is itself the return value; adding a return keyword is a compile error in expression-body form.
  • Is 'fun f() = if (c) 1 else 2' valid?
    Yes, because if is an expression in Kotlin and returns a value, so it can serve as the single expression.

Like a math formula f(x) = x*x — you state what the result equals rather than describing steps to compute it.

saying these in an interview costs you the question

  • Claiming you still need 'return' after the = sign
  • Thinking the body can contain multiple statements separated by semicolons
  • Saying expression bodies behave differently at runtime than block bodies
  • Confusing = (expression body) with == or assignment

context

open as a page

When can the return type of a single-expression function be inferred, and when must you still declare it explicitly?

level: middleimportance: must knowfreq 65%

basics

~20 s

The compiler can usually figure out the return type from the expression, so you can leave it off. But for public API functions, recursive functions, or when you want a different type than what is inferred, you should write the type explicitly.

open as a page

Show how if, when, and try-as-expression let you keep non-trivial logic in a single-expression function. What are the readability limits?

level: middleimportance: should knowfreq 50%

basics

~20 s

In Kotlin, if, when, and try all produce values, so you can use one of them as the single expression after the equals sign. This lets a one-line function branch or handle errors while still returning the result of that branch.

open as a page

What subtle bug can the elvis-style assignment '= ' equals sign introduce, e.g. fun f() = someBuilder.add(x)? Discuss inferred Unit and the single-expression-vs-assignment confusion.

level: seniorimportance: should knowfreq 35%

basics

~20 s

If the single expression returns nothing useful (Unit), the function silently returns Unit, which may not be what you intended. Also, beginners sometimes confuse the body equals sign with assigning a lambda, accidentally returning a function instead of calling it.

open as a page

As a senior, when would you mandate explicit return types on single-expression functions across a codebase, and how does this interact with overrides and binary compatibility?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

For public or library code, require explicit return types so the type is a deliberate promise that won't change by accident. For small private helpers, inference is fine. Explicit types also make overrides and shared APIs safer and more stable.

open as a page