“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”


To understand the concept of inline functions, you need to understand the implementation principle of Kotlin higher-order functions.

Underneath Lambda expressions are converted to anonymous inner class implementations, where a new anonymous class instance is created each time a Lambda expression is called, incurs additional memory and performance overhead.

To solve this problem, Kotlin introduced inline functions, which eliminate the runtime overhead of using Lambda expressions.

inline

When a higher-order function is defined, the function is an inline function with the inline keyword. The Kotlin compiler automatically replaces the code in the inline function at compile time to where it was called, does not create anonymous classes at run time, and there is no runtime overhead.

Here’s an example:

inline fun myFunc(a: Int, b: Int, operation: (Int.Int) - >Int): Int {
    val result = operation(a, b)
    return result
}

fun main(a){
    val num1 = 1
    val num2 = 2
    val result = myFunc(num1, num2) {a, b ->
        a + b
    }
    println("result= $result")}// Execution result
result= 3
Copy the code

First, the Kotlin compiler replaces the code in the Lambda expression where the function type is called with something like this:

inline fun myFunc(a: Int, b: Int, operation: (Int.Int) - >Int): Int {
    val result = a + b  // Replace the contents of the Lambda expression here
    return result
}

fun main(a){
    val num1 = 1
    val num2 = 2
    val result = myFunc(num1, num2)
    println("result= $result")}Copy the code

Then replace the code in the inline function with the code in the function call like this:

fun main(a){
    val num1 = 1
    val num2 = 2
    val result = num1 + num2 // Replace here
    println("result= $result")}Copy the code

The inline function replaces the code in the Lambda expression to the point where it is called. The code is copied each time the function is called. If the code in the Lambda expression is large, the program code will increase, saving runtime overhead at the expense of the object code.

So you should not use inline functions when a Lambda expression contains a lot of execution code, but when a Lambda expression contains only very simple code (especially single-expression), you should use inline functions. In addition, the inline keyword is only suitable to modify higher-order functions. The inline keyword provides little performance improvement for normal functions and will be prompted to remove it if it is used.

The add function, for example, uses the inline keyword:

inline fun add(a: Int, b: Int): Int {
    return a + b
}
Copy the code

The compiler gives you a prompt like this:

When using an inline function, you cannot hold a reference to a function type parameter object passed in, nor can you pass a function type parameter object passed in to another function. If you do, you will be prompted for illegal use of inline parameters. If you need to pass function arguments, one way to do this is not to use inline modifier for higher-order functions; Another way is to use the noinline keyword to decorate the function argument to be passed so that it is not inline. Here’s how noinline is used.

noinline

If a higher-order function has multiple lambdas, add inline to the function, and all the code in the Lambda expression is replaced at the point of call. If a Lambda expression has a lot of code in it, it should not be replaced. How do we prevent multiple lambdas from being inlined using the noinline keyword? Consider the following example:

inline fun testInline(block1: ()-> Unit.noinline block2: () -> Unit){}Copy the code

TestInline uses inline modifier, block2 This Lambda adds noinline modifier, so only block1 is inline, block2 is not.

crossinline

In the previous chapter, we mentioned that we cannot use return in the Lambda of a non-inlined function. We can use return in the Lambda expression of an inlined function. However, we do not use return to return the Lambda. This is because the code in the inline function’s Lambda expression is replaced at the function call. Such a return statement is called a nonlocal return.

Inline and nonlocal returns are in conflict because if the caller uses a return in a Lambda, the code after the higher-order Lambda expression cannot be executed, changing the flow of the function. Therefore, a method is needed to disable nonlocal returns in inline functions. This method modifiers the arguments of the function type with crossinline, so that a nonlocal return from a Lambda expression cannot be compiled, but local returns can be made using a return@ higher-order function name. Take this example:

After modifying the action argument with crosssinline, the return compiler reported an error in the Lambda representation, prompting us to change to return@runAction as a local return.

summary

About the knowledge of inline functions, a simple summary:

  1. The inline keyword is used to optimize the runtime overhead associated with Lambda expressions and is only suitable for higher-order functions, not normal functions.
  2. Do not inline large functions, suitable for scenarios where the code in Lambda expressions is simple.
  3. Use noinline to partially inline, leaving some of the function parameters uninline in case of multiple arguments.
  4. Use Crossinline to disallow non-local returns and avoid changing the code execution flow with returns in inline function callers’ Lambda expressions.

The resources

Principle and application of Kotlin Vocabulary | inline function

Kotlin: You have to know inline-noinline-crossinline

Relearn Kotlin – Inline, Cure-all performance medicine?