However, there are scenarios where you might not want all lambda parameters in an inline function to be inlined. This is where the noinline
modifier comes into play. In this blog, we’ll explore the purpose of noinline
, how it works, and when to use it.
noinline
?By default, when you mark a function as inline
, all the lambda parameters within that function are also inlined.
The noinline
keyword allows you to exclude specific lambda parameters from being inlined, providing greater control over how your inline functions behave.
inline fun performTask(noinline task2: () -> Unit) {}
noinline
?There are several reasons to use noinline
:
Avoid Bytecode Bloat: Prevent large or complex lambdas from being inlined, which can lead to an increase in bytecode size.
Serialization: Lambdas that need to be serialized cannot be inlined.
Higher-order Function Passing: If a lambda is passed as an argument to another function, inlining it might not work as expected.
Reflection: Lambdas marked with noinline
can be used with reflection.
noinline
Here’s an example to understand how noinline
works:
noinline
inline fun performTask(task1: () -> Unit, task2: () -> Unit) {
task1()
task2()
}
fun main() {
performTask(
{ println("Task 1") },
{ println("Task 2") }
)
}
In this example, both task1
and task2
are inlined at the call site.
noinline
inline fun performTask(task1: () -> Unit, noinline task2: () -> Unit) {
task1()
task2()
}
fun main() {
performTask(
{ println("Task 1") },
{ println("Task 2") }
)
}
In this case, only task1
is inlined, while task2
remains a regular lambda. This gives you more flexibility when handling higher-order functions.
When a lambda is passed to another function, it cannot be inlined. Using noinline
ensures compatibility.
inline fun execute(noinline task: () -> Unit) {
repeat(3) { task() }
}
fun main() {
execute { println("Executing task") }
}
Lambdas that need to be serialized cannot be inlined. Use noinline
in such scenarios.
import java.io.Serializable
inline fun saveTask(noinline task: () -> Unit): Serializable {
return object : Serializable {
val savedTask = task
}
}
fun main() {
val task = saveTask { println("Serialized Task") }
println("Task saved: $task")
}
If you need to analyze a lambda at runtime using reflection, it must not be inlined.
inline fun analyze(noinline task: () -> Unit) {
println("Lambda class: ${task::class}")
}
fun main() {
analyze { println("Analyzing lambda") }
}
noinline
Using coroutines in Android, you can leverage noinline
to pass a lambda function to another coroutine or delay execution without inlining.
import kotlinx.coroutines.*
inline fun executeTasks(
crossinline task1: suspend () -> Unit,
noinline task2: suspend () -> Unit
) {
GlobalScope.launch {
task1() // Can be inlined as it's part of the coroutine's scope
withContext(Dispatchers.Main) {
task2() // Will not be inlined; switched to the main thread
}
}
}
fun main() {
executeTasks(
task1 = {
println("Task 1 running on ${Thread.currentThread().name}")
},
task2 = {
println("Task 2 running on ${Thread.currentThread().name}")
}
)
}
In this example:
task1
is marked as crossinline
because it runs on the coroutine's background context and cannot return non-locally.
task2
is marked as noinline
because it's passed to withContext
to execute on the main thread without inlining.
noinline
?Use noinline
when:
The lambda is passed as an argument to another function.
The lambda needs to be serialized.
You need to use reflection on the lambda.
You want to avoid inlining to reduce bytecode size or complexity.
inline
Functions: Allow the compiler to copy the function body and lambdas into the call site for performance optimization.
noinline
: Excludes specific lambda parameters from being inlined, offering greater flexibility and control.
Use noinline
in scenarios involving serialization, reflection, or when passing lambdas to other functions.
Akshay Nandwana
Founder AndroidEngineers
You can connect with me on:
Join our upcoming classes
https://www.androidengineers.in/courses