Careeroza
Inline Functions
The Cost of Lambdas
Each lambda passed to a normal higher-order function becomes an object, and calling it is a virtual call. In hot loops this adds allocations. Marking the function inline makes the compiler copy the function body and the lambda body into the call site: no lambda object, no extra call.
inline fun measure(block: () -> Unit) { val t = now(); block(); log(now() - t) }
measure { work() } ─compiles to─► val t = now(); work(); log(now() - t)Non-local return
Example
Because the lambda is copied into the caller, a plain return inside it returns from the enclosing function. This is why return works inside forEach.
inline fun <T> List<T>.eachItem(action: (T) -> Unit) {
for (item in this) action(item)
}
fun findFirstExpensive(prices: List<Int>): Int? {
prices.eachItem { p ->
if (p > 1000) return p // returns from findFirstExpensive
println("checked $p")
}
return null
}
fun main() {
println("Result: ${findFirstExpensive(listOf(200, 650, 1500, 3000))}")
// a labelled return only leaves the lambda
listOf(1, 2, 3).forEach {
if (it == 2) return@forEach
println("forEach item $it")
}
}Output
checked 200 checked 650 Result: 1500 forEach item 1 forEach item 3
When to Inline
- Small functions that take lambdas:
let,apply,filter,map,use,synchronized,measureTimeMillisare all inline. - Do not inline big functions or functions without lambda parameters: the code is copied everywhere and the app gets bigger. The compiler warns you.
- Inline functions cannot be recursive and cannot access
privatemembers of their class from a public inline function.