← Back to Kotlin Course | Chapter 9: Lambdas & Higher-Order Functions | Lesson 6 of 6

Inline Functions

An inline function is copy-pasted directly into every place that calls it at compile time, which can make small helper functions with lambdas run faster.

Declaring an Inline Function

Adding inline before fun tells the compiler to insert the function's compiled code directly at each call site instead of a normal function call, which avoids extra lambda object allocation for its function-type parameters.

Example: Declaring an Inline Function

markup
inline fun measureAndRun(action: () -> Unit) {
    val start = System.currentTimeMillis()
    action()
    val time = System.currentTimeMillis() - start
    println("Took ${time}ms")
}

fun main() {
    measureAndRun {
        println("Doing some work")
    }
}

Why Inlining Avoids Overhead

Normally, passing a lambda creates an object implementing a function interface behind the scenes; inlining removes that indirection entirely by copying the lambda's code straight into the call site.

Example: Why Inlining Avoids Overhead

markup
inline fun repeatAction(times: Int, action: (Int) -> Unit) {
    for (i in 0 until times) {
        action(i)
    }
}

fun main() {
    repeatAction(3) { index ->
        println("Iteration $index")
    }
}

Non-Local Returns Require inline

A plain return inside a lambda passed to a function is only allowed when that function is inline, because the lambda's code becomes part of the calling function itself after inlining.

Example: Non-Local Returns Require inline

markup
inline fun findFirst(numbers: List<Int>, predicate: (Int) -> Boolean): Int? {
    for (n in numbers) {
        if (predicate(n)) return n
    }
    return null
}

fun main() {
    val result = findFirst(listOf(1, 2, 3, 4)) { it > 2 }
    println("First match: $result")
}

noinline and crossinline

noinline marks one specific lambda parameter as excluded from inlining (useful if it needs to be stored or passed elsewhere), while crossinline allows inlining a lambda but forbids it from performing a non-local return.

Example: noinline and crossinline

markup
inline fun runTasks(crossinline first: () -> Unit, noinline second: () -> Unit) {
    val wrapped = Runnable { first() }
    wrapped.run()
    second()
}

fun main() {
    runTasks({ println("First task") }, { println("Second task") })
}
Common Mistakes
  1. Marking a huge function inline expecting a performance win, when inlining large functions can actually bloat compiled code without meaningful benefit.
  2. Forgetting that a non-local return inside a lambda only works because the enclosing function accepting that lambda is inline.
  3. Using noinline or crossinline incorrectly on lambda parameters that don't need those special behaviors.
Chapter Summary
  • inline fun tells the compiler to substitute the function's body (and its lambda parameters) directly at each call site.
  • Inlining avoids the runtime overhead of creating a separate object for each lambda passed to the function.
  • Non-local returns from a lambda are only possible because the function receiving it is inlined.
  • noinline marks a specific lambda parameter as exempt from inlining, and crossinline forbids non-local returns from a specific inlined lambda.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.