A function type like (Int, Int) -> Int describes a function taking two Ints and returning an Int, and such types can be used anywhere a normal type can — as a parameter, a return type, or a variable's type. When the last parameter of a function is itself a function, Kotlin lets the lambda argument be written OUTSIDE the parentheses (or replace an empty pair of parentheses entirely), which is precisely the syntax that makes calls like list.filter { it > 5 } or repeat(3) { println(it) } read naturally. Inside a single-parameter lambda, it is the implicit name for that parameter unless a different name is given explicitly.
Function types and basic lambda syntax
operation's type, (Int, Int) -> Int, says exactly what kind of function is expected — any lambda or function reference matching that shape can be passed.
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
val sum = calculate(3, 4, { x, y -> x + y }) // ordinary call, lambda as the last argument
println(sum) // 7Trailing lambda syntax: the idiomatic form
Since operation is the LAST parameter, the lambda can move entirely outside the parentheses — this exact rule is why list.filter { ... } and similar calls read so naturally, almost like a built-in language construct rather than an ordinary function call.
val sum = calculate(3, 4) { x, y -> x + y } // trailing lambda — moved OUTSIDE the parens
val numbers = listOf(1, 2, 3, 4, 5, 6)
val evens = numbers.filter { it % 2 == 0 } // 'it' — implicit name for a single parameter
println(evens) // [2, 4, 6]Returning a function from a function
makeMultiplier returns an actual function — the returned lambda captures factor from its enclosing scope, a closure that keeps working correctly even after makeMultiplier itself has returned.
fun makeMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor } // captures 'factor' — a closure
}
val triple = makeMultiplier(3)
println(triple(5)) // 15