skip to content

HOF Declaration & Usage

A higher-order function names a function type in its parameters or return, and callers can pass a lambda, a reference, or a stored function value. Being comfortable declaring one — not just calling map — is the bar here.

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

questions

5

What is a higher-order function in Kotlin, and how do you declare a function that takes another function as a parameter?

level: juniorimportance: must knowfreq 85%

answer

  1. HOF = takes a function OR returns one
  2. Param type: (In) -> Out
  3. Call it: f(x) is sugar for f.invoke(x)
  4. Last param function-typed => trailing lambda
  5. Functions are first-class values

basics

~10 s

A higher-order function takes a function as a parameter or returns one. You declare the parameter with a function type like (Int) -> Int, then call it inside the body.

solid answer

~40 s

A higher-order function (HOF) either takes a function-typed parameter or returns a function. You declare a parameter using a function type written as (ParamTypes) -> ReturnType, e.g. fun apply(x: Int, f: (Int) -> Int): Int = f(x). At the call site you pass a lambda { it + 1 }, a function reference ::inc, or any value of that function type. Inside the body you invoke the parameter like a normal function: f(x), or explicitly f.invoke(x). Kotlin models function types as the FunctionN interfaces (Function1, Function2, ...) under the hood, but you almost always write the arrow syntax. If the last parameter is a function type, callers may use trailing-lambda syntax: apply(5) { it + 1 }.

code

kotlin · 10 lines
kotlin
fun apply(x: Int, f: (Int) -> Int): Int = f(x)

fun increment(n: Int) = n + 1

fun main() {
    println(apply(5) { it + 1 })   // lambda -> 6
    println(apply(5, ::increment)) // reference -> 6
    val triple: (Int) -> Int = { it * 3 }
    println(apply(5, triple))      // stored value -> 15
}

go deeper

for a junior

Defines HOF, writes a (Int)->Int parameter, and calls it with a lambda.

for a middle

Also passes function references and stored values, and knows trailing-lambda rules.

for a senior

Explains the FunctionN/invoke desugaring and when each calling form reads best.

for a principal

Frames HOFs as first-class-function support and the basis for the collection/coroutine APIs and DSLs.

## What is a higher-order function? A **higher-order function (HOF)** is a function that does at least one of: - takes a **function** as a parameter, or - **returns** a function. This is possible because in Kotlin functions are *first-class values* — they can be stored in variables, passed around, and returned. ## Function types A **function type** describes the shape of a function value. It is written `(ParameterTypes) -> ReturnType`: - `(Int) -> Int` — takes one `Int`, returns an `Int`. - `() -> Unit` — takes nothing, returns nothing meaningful (`Unit`). - `(String, Int) -> Boolean` — two params, returns `Boolean`. - `(Int) -> Unit` — a receiver-less consumer of an `Int`. ## Declaring a HOF parameter ```kotlin fun apply(x: Int, f: (Int) -> Int): Int { return f(x) // invoke the function value } ``` Here `f` has type `(Int) -> Int`. Inside the body you **call** it like any function: `f(x)`. You can also write `f.invoke(x)` — the `()` call syntax is sugar for the `invoke` operator. ## Calling a HOF You can pass: - a **lambda**: `apply(5) { it + 1 }` — `it` is the single implicit parameter. - a **function reference**: `apply(5, ::increment)` where `fun increment(n: Int) = n + 1`. - a **stored value**: `val g: (Int) -> Int = { it * 2 }; apply(5, g)`. ## Trailing lambda If the **last** parameter is a function type, the lambda can go *outside* the parentheses: ```kotlin apply(5) { it + 1 } ``` If the function type is the *only* parameter, you can drop the parentheses entirely: `run { ... }`. ## Under the hood Function types compile to the `kotlin.FunctionN` interfaces (`Function0`, `Function1`, ... up to 22), each with an `invoke` operator. You normally never see these — the arrow syntax is the idiomatic surface.

  • What does f.invoke(x) have to do with f(x)?
    They are equivalent. `()` call syntax on a function value desugars to the `invoke` operator on the FunctionN interface.
  • Can a HOF take a parameter that returns Unit?
    Yes, e.g. (Int) -> Unit. It is a consumer/side-effecting callback; you still call it as f(x) and ignore the Unit result.

A function type is like a job description; a lambda or reference is a worker you hand in to fill that role.

saying these in an interview costs you the question

  • Thinking only lambdas can be passed, not function references or stored values
  • Writing the parameter as 'f: Function' instead of a typed (In) -> Out
  • Confusing a HOF with a function that merely contains a lambda internally
  • Believing you must call f.invoke() and that f(x) is invalid

context

open as a page

When calling a higher-order function, what are the different ways to pass the function argument (lambda, reference, stored value), and how do nullable and receiver function types appear in a HOF signature?

level: middleimportance: should knowfreq 60%

basics

~10 s

You can pass a lambda, a function reference like ::name or obj::method, or a stored function value. A function-type parameter can be nullable, like ((Int)->Int)?, and can declare a receiver, like Int.()->String.

open as a page

How do you write a function that RETURNS a function in Kotlin, and what is captured when the returned lambda references the enclosing function's parameters?

level: middleimportance: should knowfreq 65%

basics

~10 s

Give the function a function-type return, like (Int) -> Int, and return a lambda. The lambda remembers (captures) the outer variables it uses, so each call can make a customized function.

open as a page

What is the runtime cost of passing lambdas to higher-order functions in Kotlin, and how does the inline modifier change that? Explain noinline and crossinline.

level: seniorimportance: should knowfreq 55%

basics

~20 s

Normally a lambda becomes an object, which costs an allocation. Marking the higher-order function inline copies its body and the lambda into the call site, removing that object. noinline and crossinline tweak which lambdas get inlined.

open as a page

You are designing a public API. When should a parameter be a function type (HOF) versus a single-abstract-method interface, and what signature design choices make a HOF parameter pleasant to call?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

Use a function-type parameter for simple one-shot callbacks so callers pass a quick lambda. Use a named interface when the callback has several methods, needs documentation, or must be implemented/reused. Put the lambda last so trailing-lambda syntax works.

open as a page