Kotlin noinline Keyword
last modified April 19, 2025
Kotlin's inline functions optimize higher-order functions by inlining lambda
bodies. The noinline
modifier gives control over which lambdas
should not be inlined. This tutorial explores noinline
in depth.
Basic Definitions
The noinline
keyword in Kotlin marks a lambda parameter that should
not be inlined when the containing function is inlined. It's used with inline
functions to exclude specific lambdas from inlining. This preserves the lambda
as a real object when needed.
Basic noinline Usage
The simplest use of noinline
is to mark one lambda parameter in an
inline function. This prevents that specific lambda from being inlined while
others still are.
package com.zetcode inline fun process( action: () -> Unit, noinline logger: (String) -> Unit ) { logger("Starting process") action() logger("Process completed") } fun main() { process( { println("Performing action") }, { msg -> println("[LOG] $msg") } ) }
Here, logger
is marked as noinline
while action
is inlined. The logger lambda remains a function object, allowing it to be stored
or passed around if needed. The action lambda is inlined at the call site.
Why Use noinline
The main reason to use noinline
is when you need to treat a lambda
as an object. Inlined lambdas can't be stored in variables or passed as objects.
noinline
preserves the lambda's object nature.
package com.zetcode inline fun execute( task: () -> Unit, noinline callback: () -> Unit ) { val savedCallback = callback // Only possible with noinline task() savedCallback() } fun main() { execute( { println("Task executed") }, { println("Callback invoked") } ) }
This example shows storing a callback lambda in a variable. Without
noinline
, this would be impossible because inlined lambdas don't
exist as objects. The noinline
modifier makes this operation valid.
Mixing Inline and noinline
You can mix inlined and non-inlined parameters in the same function. This gives fine-grained control over which lambdas should be optimized and which should remain as objects.
package com.zetcode inline fun transform( data: List<Int>, noinline validator: (Int) -> Boolean, converter: (Int) -> Int ): List<Int> { return data.filter(validator).map(converter) } fun main() { val numbers = listOf(1, 2, 3, 4, 5) val result = transform(numbers, { it % 2 == 0 }, // Not inlined { it * 2 } // Inlined ) println(result) // Output: [4, 8] }
Here, validator
is not inlined (can be passed to filter
),
while converter
is inlined. This demonstrates selective optimization
where only performance-critical lambdas are inlined.
noinline with Crossinline
noinline
can be combined with crossinline
to control
lambda behavior further. crossinline
prevents non-local returns
while still inlining the lambda.
package com.zetcode inline fun runOperations( crossinline op: () -> Unit, noinline completion: () -> Unit ) { try { op() } finally { completion() } } fun main() { runOperations( { println("Operation running") }, { println("Operation completed") } ) }
The op
lambda is cross-inlined (no non-local returns allowed), while
completion
is not inlined at all. This combination is useful for
control flow-sensitive operations with required callbacks.
noinline in Real-world Scenarios
In real applications, noinline
is often used with callback-heavy
APIs. It allows passing callbacks to other functions while still benefiting from
inlining for performance-critical parts.
package com.zetcode inline fun fetchData( noinline onSuccess: (String) -> Unit, noinline onError: (Exception) -> Unit ) { try { // Simulate data fetching val data = "Sample data" onSuccess(data) } catch (e: Exception) { onError(e) } } fun main() { fetchData( { data -> println("Received: $data") }, { error -> println("Error: ${error.message}") } ) }
Both callbacks are marked noinline
because they might be called
asynchronously or passed around. This pattern is common in network request
handlers or database operations where callbacks are essential.
Performance Considerations
While inlining improves performance by reducing function object allocations,
noinline
trades some performance for flexibility. Use it judiciously
where lambda objects are truly needed.
package com.zetcode inline fun benchmark( noinline setup: () -> Unit, action: () -> Unit, noinline teardown: () -> Unit ) { setup() val start = System.nanoTime() action() val duration = System.nanoTime() - start teardown() println("Operation took ${duration}ns") } fun main() { benchmark( { println("Setting up") }, { List(1000) { it }.sum() }, { println("Cleaning up") } ) }
Here, the performance-critical action
is inlined while setup/teardown
are not. This optimizes the hot path while keeping infrastructure code flexible.
Measure performance when deciding what to inline.
Limitations of noinline
noinline
parameters have restrictions. They can't be called in
non-inline contexts like nested objects. They also can't be used with certain
inline-only operations like return
from enclosing function.
package com.zetcode inline fun problematic( noinline block: () -> Unit ) { val runnable = object : Runnable { override fun run() { block() // Error: Can't use noinline lambda here } } // ... }
This code won't compile because noinline
lambdas can't be used in
object expressions. The compiler enforces this to maintain consistency in lambda
handling across different contexts.
Best Practices for noinline
- Use sparingly: Only apply
noinline
when you need lambda objects for storage or passing. - Profile performance: Measure the impact before deciding which
lambdas to mark as
noinline
. - Combine wisely: Mix
noinline
with regular andcrossinline
parameters for optimal control. - Document reasons: Comment why a parameter is
noinline
for future maintainers. - Consider alternatives: Sometimes restructuring code can
avoid the need for
noinline
.
Source
Kotlin Inline Functions Documentation
This tutorial covered Kotlin's noinline
keyword in depth, showing
its purpose and practical applications. We explored various scenarios where
noinline
is essential and discussed its performance implications.
Proper use of noinline
helps balance flexibility and optimization.
Author
List all Kotlin tutorials.