Adding the inline modifier to a higher-order function will result in all passed lambdas being inlined at the call site. However, there may be cases where this is not what you want. For these situations, we can make use of noinline.
We can add the noinline modifier to a function parameter of our higher-order function. This will indicate to the compiler to not inline that particular lambda. Let's explore this using our previous example:
- Let's add a second function parameter to safelyRun():
inline fun safelyRun(action: () -> Unit, action2:() -> Unit) {
try {
action()
action2()
} catch (error: Throwable) {
println("Caught error: ${error.message}")
}
}
- Now, we will update our usage to pass a second lambda:
fun main() {
val greeting = "Hello"
safelyRun({ println("Hi Kotlin")}) {
println("$greeting Kotlin")
}
}
- If we look at the generated code, we'll see that it looks very similar to before, with both lambdas being inlined at the call site:
public static final void main() {
String greeting = "Hello";
boolean var1 = false;
try {
int var7 = false;
String var8 = "Hi Kotlin";
boolean var4 = false;
System.out.println(var8);
var7 = false;
var8 = greeting + " Kotlin";
var4 = false;
System.out.println(var8);
} catch (Throwable var6) {
String var2 = "Caught error: " + var6.getMessage();
boolean var3 = false;
System.out.println(var2);
}
}
- But now, let's add noinline to the action2 parameter:
inline fun safelyRun(action: () -> Unit, noinline action2:() -> Unit) {
...
}
- Now, the generated code will not inline the second lambda, but will instead create a Function0 instance to capture the required local state required for the lambda:
public static final void main() {
final String greeting = "Hello";
Function0 action2$iv = (Function0)(new Function0() {
// $FF: synthetic method
// $FF: bridge method
public Object invoke() {
this.invoke();
return Unit.INSTANCE;
}
public final void invoke() {
String var1 = greeting + " Kotlin";
boolean var2 = false;
System.out.println(var1);
}
});
boolean var2 = false;
String var4;
boolean var5;
try {
int var3 = false;
var4 = "Hi Kotlin";
var5 = false;
System.out.println(var4);
action2$iv.invoke();
} catch (Throwable var6) {
var4 = "Caught error: " + var6.getMessage();
var5 = false;
System.out.println(var4);
}
}
With inline and noinline, you have great control over how the compiler will treat any function parameters you define for your higher-order functions. IntelliJ-based IDEs will also warn you when the performance impact of inlining functions is negligible.