Kotlin Inline Functions
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
Please Login to comment...