Open In App

Kotlin Inline Functions

Improve
Improve
Like Article
Like
Save
Share
Report

In Kotlin, the higher-order functions or lambda expressions, all stored as an object so memory allocation, for both function objects and classes, and virtual calls might introduce runtime overhead. Sometimes we can eliminate the memory overhead by inlining the lambda expression. In order to reduce the memory overhead of such higher-order functions or lambda expressions, we can use the inline keyword which ultimately requests the compiler to not allocate memory and simply copy the inlined code of that function at the calling place.
 
Example:

Kotlin




fun higherfunc( str : String, mycall :(String)-> Unit) {
   
    // inovkes the print() by passing the string str
    mycall(str)
}
 
// main function
fun main(args: Array<String>) {
    print("GeeksforGeeks: ")
    higherfunc("A Computer Science portal for Geeks",::print)
}


Bytecode: Like Java, Kotlin is also platform independent language so it converts into the bytecode first. We can get the bytecode as Tools -> Kotlin -> Show Kotlin Bytecode. Then, decompile to get this bytecode.
 

In the above bytecode, the main part to focus on is:

mycall.invoke(str)

mycall invokes the print function by passing the string as a parameter. While invoking the print(), it would create an additional call and increases memory overhead.
It works like

mycall(new Function() {
        @Override
        public void invoke() {
         //println statement is called here.
        }
    });

If we call a large number of functions as parameters each of them would add up to the method count then there is a vast impact on the memory and performance.
 

What inline keyword will do in the above program?

Kotlin




inline fun higherfunc( str : String, mycall :(String)-> Unit){
    // inovkes the print() by passing the string str
    mycall(str)
}
// main function
 fun main(args: Array<String>) {
    print("GeeksforGeeks: ")
    higherfunc("A Computer Science portal for Geeks",::print)
}


Bytecode: 
 

With the help of the inline keyword, the println lambda expression is copied in the main function in the form of System.out.println and no further calls required.
 

Non-Local control Flow

In Kotlin, if we want to return from a lambda expression then the Kotlin compiler does not allow us to do so. With the help of the inline keyword, we can return from the lambda expression itself and exit the function in which inlined function is called.
Kotlin Program of Using Return in Lambda Expression:
 

Kotlin




var lambda = { println("Lambda expression"
              return }      // normally lambda expression does not allow return
                           // statement, so gives compile time error
fun main(args: Array<String>) {
    lambda()
}


Output:  

Error:(4, 5) Kotlin: 'return' is not allowed here

Normally it does not allow to return from lambda and it gives an error.
 

Kotlin




var lambda1 = { println("Lambda expression")}
 
fun main(args: Array<String>) {
    lambda1()
}


Output: 

Lambda expression

Normally without it works fine and print the statement.
Kotlin Program of Using Return in Lambda While Passing as an Argument to Inlined Function: 

Kotlin




fun main(args: Array<String>){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
    return },      // inlined function allow return
                   // statement in lambda expression
                   // so, does not give compile time error
 
    { println("Lambda expression 2")} )
 
    println("Main function ends")
}
    // inlined function
inline fun inlinedFunc( lmbd1: () -> Unit, lmbd2: () -> Unit  ) { 
    lmbd1()
    lmbd2()
}


Output: 
 

Main function starts
Lambda expression 1

Explanation: Here, we passed two lambda expressions as arguments to the inlinedFunc() function. While calling the inlined function from the main, we pass both as to its arguments. In the inlined function, lmbd1() invoked the first expression and return keyword force the lambda expression itself and the main function from where it is called to exit.

crossline keyword

In the above program, return in lambda exits the inline function as well as its enclosing function. So to stop returning from the lambda expression we can mark it using the crossline. It will throw a compiler error if sees any return statement in the Lambda expression.
Example: 

Kotlin




fun main(args: Array<String>){
    println("Main function starts")
     inlinedfunc({ println("Lambda expression 1")
        return },     // It gives compiler error
         { println("Lambda expression 2")} )
 
    println("Main function ends")
}
 
inline fun inlinedfunc( crossinline lmbd1: () -> Unit, lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}


Output:  

Error:(6, 9) Kotlin: 'return' is not allowed here

Noinline

In Kotlin, if we want only some of the lambdas passed to an inline function to be inlined, we can mark some of the function parameters with the noinline modifier.
 

Kotlin




fun main(args: Array<String>){
    println("Main function starts")
    inlinedFunc({ println("Lambda expression 1")
        return },     // It does not compiler time error
        { println("Lambda expression 2")
            return } )    // It gives compiler error
 
    println("Main function ends")
}
 
inline fun inlinedFunc( lmbd1: () -> Unit, noinline lmbd2: () -> Unit  ) {
    lmbd1()
    lmbd2()
}


Output:  

Error:(11, 13) Kotlin: 'return' is not allowed here

Reified Type Parameters

Sometimes we need to access the type of parameter passed during the call. We have to simply pass the parameter at the time of function calling and we can retrieve the type of the parameter using a reified modifier.
 

Kotlin




fun main(args: Array<String>) {
    genericFunc<String>()
}
 
inline fun <reified T> genericFunc() {
    print(T::class)
}


Output:  

class kotlin.String

Inline Properties

Inlined function copy the code to the calling place, similarly inline keyword copy the inline properties accessor methods to calling place. The inline modifier can be used on accessors of properties that don’t have a backing field. 
 

Kotlin




fun main(args: Array<String>) {
    print(flag)
}
fun foo(i: Int ): Int{
    var a =  i
    return a
}
inline var flag : Boolean
    get() = foo(10 ) == 10
    set(flag) {flag}


Output:  

true


Last Updated : 30 Nov, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads