Higher-Order Functions: Passing Code as Data

Higher-order functions treat code as data, accepting other functions as arguments. Lambdas are a concise syntax for creating these function arguments inline, powering collection operations like map and filter or UI listeners.
Why it exists
Higher-order functions exist to create more abstract, expressive, and reusable code. Instead of writing a custom loop for every list transformation, you can write one generic function (like map or filter) and pass in the specific logic as a parameter. This separates the general mechanism of iteration from the specific action you want to perform on each element.
The mental model
Think of functions in Kotlin as first-class citizens, just like integers or strings. You can store a function in a variable, pass it into another function, or have a function return a new function. A higher-order function is simply a function that operates on other functions. Lambdas are a convenient shorthand for creating these function "values" on the fly, without needing to formally declare them with the fun keyword.
How it works
Kotlin uses special "function types" to make this statically safe. A type like (Int, String) -> Boolean declares a variable or parameter that must hold a function taking an Int and a String and returning a Boolean. A higher-order function declares a parameter with one of these function types. For example, Collection.fold takes a combine parameter of type (R, T) -> R. When you call the function, you must provide an implementation that matches this type signature. You can provide this implementation in several ways, most commonly with a lambda expression like { acc, i -> acc + i }, an anonymous function, or a reference to an existing function like Int::plus.
When to use it
Use higher-order functions and lambdas to abstract control structures and behavior. This is ideal for collection processing (map, filter, forEach), defining callbacks for asynchronous tasks, setting up UI event listeners like setOnClickListener, and building flexible APIs where the caller supplies the specific logic.
When not to use it
Avoid using lambdas when their internal logic becomes complex, spanning multiple lines with side effects. In such cases, a traditional private, named function is more readable and easier to test; you can then pass a reference to that function. Also, be mindful of performance in very tight, performance-critical loops. While the Kotlin compiler often inlines lambdas to eliminate overhead, creating function objects can have a small cost compared to a direct, imperative loop.
One canonical example
A common use case is transforming a list. To double every number in a list of integers, you can use the map higher-order function.
val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 }Here, map is the higher-order function. It takes a function of type (Int) -> R as its argument. The lambda expression { it * 2 } is the function we pass. it is the default name for a single-parameter lambda. The code iterates through numbers, applies the lambda to each element, and collects the results into a new list, doubled, which will contain [2, 4, 6].
Interview question
What is the primary purpose of using a lambda expression when working with higher-order functions in Kotlin?
- a.To provide a compact, anonymous function implementation directly as an argument.Correct
- b.To ensure that the function passed as an argument is always inlined by the compiler.
- c.To declare a reusable, named function that can be referenced multiple times.
- d.To explicitly define the function type signature for a parameter.
Why? this is the answer
Lambdas serve as a concise, anonymous way to define and pass function implementations directly as arguments to higher-order functions. While inlining can occur, it's a compiler optimization, not the primary purpose of using a lambda; lambdas are inherently anonymous, unlike named functions.
Just read this? Test yourself on what you have been reading.
Read the original → kotlinlang.org
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on kotlin — each one lists the topics its interview covers.
See open roles