What is a higher-order function in Kotlin, and how do you declare a function that takes another function as a parameter?
answer
- HOF = takes a function OR returns one
- Param type: (In) -> Out
- Call it: f(x) is sugar for f.invoke(x)
- Last param function-typed => trailing lambda
- Functions are first-class values
basics
~10 sA 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 sA 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 linesfun 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
Defines HOF, writes a (Int)->Int parameter, and calls it with a lambda.
Also passes function references and stored values, and knows trailing-lambda rules.
Explains the FunctionN/invoke desugaring and when each calling form reads best.
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