Been working with crossinline inline and noinline for while, but never understood crossinline 100% percent. I Did deeper reading and tried to do some coding examples by myself and would like to talk about one situation.
So crossinline disables possibility of adding return to our lambda function (correct me if I'm wrong here). Lets see example:
inline fun higherOrderFunction(lambda : () -> Unit){
lambda.invoke()
Toast.makeText(this, "test", Toast.LENGTH_SHORT).show()
}
And I call this function like this:
higherOrderFunction {
print("E Numbers Detector android app is the best")
return
}
Works fine. Keep in mind that in this case Toast is not executed due to the return that is called. If I put crossinline on my lambda:
inline fun higherOrderFunction(crossinline lambda : () -> Unit){.......
I won't be able to use return in the place that I put it. So it disables return in lambda. But does it?
What if I do workaround And put lambda code in some other function and add return:
inline fun higherOrderFunction(lambda : () -> Unit){
lambda.invoke()
Toast.makeText(this, "test", Toast.LENGTH_SHORT).show()
}
This part up stays the same. But now I add function:
fun testLambdaFunction() {
print("E Numbers Detector android app is the best")
return
}
And do the call like this:
higherOrderFunction {
testLambdaFunction()
}
If I do that, everything works fine, Toast is printed and my lambda function has a return in itself even though I use crossinline to disable it.
Why is this so? Isn't this "return" part of our lambda that we sent as a parameter?
CodePudding user response:
When you have a return
in higherOrderFunction()
's lambda, the function which 'returns' is the higherOrderFunction()
, while when you return
in testLambdaFunction()
the function which 'returns' is just the testLambdaFunction()
itself. More or less think of crossinline
as a toggle to whether allow a lambda to end your calling function's execution prematurely or not.
Keep in mind that calls of functions with inline
keyword no longer exist after compilation. What basically happens is that their body is being copy-pasted to their previous function call (not precisely, I'm simplifying a bit). With that in mind, let's deconstruct the above examples.
~ inline example https://pl.kotl.in/VCwMsea_n
inline fun higherOrderFunction(lambda : () -> Unit) {
lambda.invoke()
println("test")
}
fun main() {
higherOrderFunction {
print("E Numbers Detector android app is the best")
return
}
}
This is equivalent to the below code if we could theoretically deconstruct the inline function into Kotlin code.
~ deconstructed inline example https://pl.kotl.in/rbXgSnBlQ
fun main() {
print("E Numbers Detector android app is the best")
return
println("test")
}
As you can see the return
makes the main()
function to end and thus the "test" is never printed.
~ crossinline example https://pl.kotl.in/bJdEm8QbR
inline fun higherOrderFunction(crossinline lambda : () -> Unit) {
lambda.invoke()
println("test")
}
fun testLambdaFunction() {
println("E Numbers Detector android app is the best")
return
println("This code is unreachable")
}
fun main() {
higherOrderFunction {
testLambdaFunction()
}
}
As you can see this time the return
ends the testLambdaFunction()
not the main()
.
~ deconstructed crossinline example https://pl.kotl.in/6R3K7P21D
fun testLambdaFunction() {
println("E Numbers Detector android app is the best")
return
println("This code is unreachable")
}
fun main() {
testLambdaFunction()
println("test")
}
The main()
function doesn't end until after printing "text", as there's no return
called in it.