Kotlin Inline Functions
In Kotlin, higher-order functions and lambda expressions are treated like objects. This means they can use up memory, which can slow down your program. To help with this, we can use the 'inline' keyword. This keyword tells the compiler not to create separate memory spaces for these functions. Instead, it copies the code directly into the place where the function is called. This way, we can save memory and improve performance.
Example:
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)
}
Output:
GeeksforGeeks: A Computer Science portal for Geeks
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?
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)
}
Output:
GeeksforGeeks: A Computer Science portal for Geeks
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:
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.
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:
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:
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
No inline
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.
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.
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.
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