49. Inline Functions

Marking a higher-order function inline tells the compiler to copy its body — and the bodies of its lambda arguments — directly into each call site. This avoids allocating a function object for the lambda and, as a bonus, allows non-local returns from inside the lambda.

inline fun measure(label: String, block: () -> Unit) {
    val start = System.nanoTime()
    block()
    val elapsed = System.nanoTime() - start
    println("$label finished (elapsed ${if (elapsed >= 0) ">= 0" else "?"} ns)")
}

inline fun firstEven(numbers: List<Int>): Int? {
    numbers.forEach {
        if (it % 2 == 0) return it   // non-local return, enabled by inlining
    }
    return null
}

fun main() {
    measure("sum") {
        var sum = 0
        for (i in 1..1000) sum += i
        println("sum = $sum")
    }

    println("first even: ${firstEven(listOf(1, 3, 4, 7))}")
}

Because the lambda is inlined, the return it inside forEach returns from firstEven itself, not just from the lambda. Two modifiers tune this behavior: mark a lambda parameter noinline to keep it as a real function object (for example, to store or pass it on), and crossinline to forbid non-local returns when the lambda will be invoked from another execution context.

Running it:

$ kotlin run
sum = 500500
sum finished (elapsed >= 0 ns)
first even: 4
← Prev Index Next →