← 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.
Syntax
kotlin
inline fun functionName(action: () -> Unit) {
    // body and lambda are copied to the call site
    action()
}

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) {
    // Declare a read-only variable `start`, set to `System.currentTimeMillis()`
    val start = System.currentTimeMillis()
    action()
    // Declare a read-only variable `time`, set to `System.currentTimeMillis() - start`
    val time = System.currentTimeMillis() - start
    // Print "Took ${time}ms" to the console, with a trailing newline
    println("Took ${time}ms")
}

// Entry point: execution of the program starts here
fun main() {
    measureAndRun {
        // Print "Doing some work" to the console, with a trailing newline
        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) {
    // Loop over `0 until times`, binding each item to `i`
    for (i in 0 until times) {
        action(i)
    }
}

// Entry point: execution of the program starts here
fun main() {
    repeatAction(3) { index ->
        // Print "Iteration $index" to the console, with a trailing newline
        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? {
    // Loop over `numbers`, binding each item to `n`
    for (n in numbers) {
        if (predicate(n)) return n
    }
    // Return `null` from this function
    return null
}

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `result`, set to `findFirst(listOf(1, 2, 3, 4)) { it > 2 }`
    val result = findFirst(listOf(1, 2, 3, 4)) { it > 2 }
    // Print "First match: $result" to the console, with a trailing newline
    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) {
    // Declare a read-only variable `wrapped`, set to `Runnable { first() }`
    val wrapped = Runnable { first() }
    wrapped.run()
    second()
}

// Entry point: execution of the program starts here
fun main() {
    runTasks({ println("First task") }, { println("Second task") })
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
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.