skip to content

How Kotlin Does Functions-as-Values

Lambdas and function references are real values with types like (A) -> B, backed by FunctionN objects on the JVM — unless the higher-order function is inline, in which case they vanish at compile time. Holding both halves of that picture is what interviewers are checking.

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

questions

5

In Kotlin, what does a function type like (Int) -> String mean, and how can you store a function in a variable?

level: juniorimportance: must knowfreq 80%

answer

  1. (Params) -> ReturnType
  2. () is sugar for invoke()
  3. lambda / anon fun / reference all fit a function type
  4. nullable needs extra parens: ((Int)->Unit)?
  5. receiver type: Int.() -> String

basics

~20 s

A function type describes a function's inputs and output. (Int) -> String means: takes an Int, returns a String. You can put such a function in a variable and call it later like a normal function.

solid answer

~40 s

Kotlin treats functions as first-class values, so a function type is a real type. (Int) -> String denotes a function taking an Int and returning a String. You assign a lambda, an anonymous function, or a function reference to a variable of that type: val f: (Int) -> String = { it.toString() }, then invoke it with f(5) or f.invoke(5). The type can include a receiver (Int.() -> String) and be nullable ((Int) -> String?). Because the value is a real object, you can pass it to other functions, return it, or store it in collections. Under the hood the compiler represents it as a FunctionN interface implementation, but at the source level you just treat it like any typed value.

code

kotlin · 7 lines
kotlin
val area: (Int, Int) -> Int = { w, h -> w * h }
val ops: Map<String, (Int, Int) -> Int> = mapOf(
    "add" to { a, b -> a + b },
    "area" to area
)
println(ops["add"]!!(2, 3))   // 5
println(ops["area"]!!(4, 5))  // 20

go deeper

for a junior

Knows the (A) -> B syntax, can store a lambda in a typed variable and call it.

for a middle

Adds nullable and receiver function types, and the invoke operator equivalence.

for a senior

Explains the FunctionN object behind the value and how it enables higher-order functions.

for a principal

Frames function types as the type-system foundation for passing behavior, DSLs, and API design across modules.

## What a function type is Kotlin has **first-class functions**: a function can be used like any other value — stored in a variable, passed as an argument, or returned. To type such a value, Kotlin provides **function types**. The syntax `(P1, P2) -> R` lists parameter types in parentheses and the return type after the arrow `->`: - `() -> Unit` — no params, returns `Unit` (nothing useful) - `(Int) -> String` — takes an `Int`, returns a `String` - `(String, Int) -> Boolean` — two params, returns `Boolean` ## Storing and calling a function value ```kotlin val toText: (Int) -> String = { n -> n.toString() } val len: (String) -> Int = String::length // function reference println(toText(5)) // "5" — call like a normal function println(toText.invoke(5)) // identical; invoke() is the operator behind () println(len("hello")) // 5 ``` The `()` call syntax is sugar for the `invoke` operator that every function value exposes. ## Variations - **Nullable function type:** `val cb: ((Int) -> Unit)? = null` — note the extra parentheses. - **Receiver type:** `val greet: String.() -> String = { "Hi $this" }`, called as `"Sam".greet()`. The receiver becomes `this` inside the lambda. - **Returned from a function:** functions can produce other functions (higher-order functions). ## What it compiles to A function value is an object implementing a `FunctionN` interface (`Function1<Int, String>` here) whose single method is `invoke`. You rarely see this directly, but it explains why a lambda is an object you can pass around. ## Why it matters Function types are what make `map`, `filter`, callbacks, and DSLs possible — they let you pass behavior, not just data.

  • How do you write a nullable function type, and why are the extra parentheses needed?
    ((Int) -> Unit)? — without the outer parens, Int -> Unit? would mean a function returning a nullable Unit, not a nullable function.
  • What is the difference between calling f(x) and f.invoke(x)?
    None functionally; f(x) is syntactic sugar that the compiler lowers to the invoke operator call f.invoke(x).

A function type is like a job description: it says what inputs go in and what comes out, so any worker (lambda, reference) matching it can be hired into the slot.

saying these in an interview costs you the question

  • Thinking a function type is the same as a Kotlin function declaration (fun)
  • Writing (Int) -> Unit? when meaning a nullable callback
  • Believing you must use invoke() explicitly to call a stored function
  • Confusing function type with functional interface (SAM) syntax
  • Saying functions can't be stored in variables in Kotlin

context

open as a page

What is a higher-order function in Kotlin? Show how to write one that takes a function as a parameter and one that returns a function.

level: middleimportance: must knowfreq 70%

basics

~10 s

A higher-order function takes a function as an argument, returns a function, or both. For example, map takes a transform function. You declare the parameter with a function type and call it inside.

open as a page

What is the difference between a lambda, an anonymous function, and a callable (function/property) reference in Kotlin, and when would you use each?

level: middleimportance: must knowfreq 75%

basics

~20 s

All three produce a function value. A lambda is the short { } form. An anonymous function uses fun(...) {...} with an explicit return type. A reference like ::foo points at existing code instead of rewriting it.

open as a page

What object does a Kotlin lambda actually become at runtime, and what are the performance implications of passing functions as values?

level: seniorimportance: should knowfreq 55%

basics

~10 s

A lambda becomes an object implementing a FunctionN interface (like Function1) with an invoke method. Creating these objects and capturing variables can add allocations, which inline functions can remove.

open as a page

How do Kotlin function types relate to Java functional (SAM) interfaces, and when does SAM conversion apply?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Java interfaces with one method (like Runnable) can accept a lambda through SAM conversion. Kotlin's own function types are different objects, but you can mark a Kotlin interface 'fun interface' to allow lambdas too.

open as a page