```inline fun test(crossinline callback: () -> ...
# getting-started
t
Copy code
inline fun test(crossinline callback: () -> Unit){
    callback()
}
The doc says: some
inline
functions may call the lambdas passed to them as parameters not directly from the function body, but from another execution context, such as a local object or a nested function.
which I understood as: an
inline
function is not allowed to call the
crossinline
parameter directly in its scope, ...
But why does the code snippet works and I was able to call
callback()
directly? Does the doc meant to say that you can call the
crossinline
argument directly and within another local scope as well?
j
Yes, the
crossinline
modifier allows you to use the argument in other scopes in addition to being able to use it directly. It does so by forbidding non-local returns inside the lambda that is passed on the call site.
So what you're forbidding with this
crossinline
is this kind of usage:
Copy code
fun someOtherFun() {
    // calling test() with a non-local return
    // that tries to return from someOtherFun
    test {
        return // compile error due to crossinline
    }
}
t
Ok looks like I misunderstood the docs then because of the phrase not directly from the function body which confused the heck out of me. Can I think if
crossinline
as hybrid then? The
crossinline
makes the lambda argument
hybrid
in the sense that it can be used in other scopes (like
noinline
) but cannot have non-local control flow (like
inline
)
wait hold on maybe not, the
inline
can have return
j
Yes, in a way. Basically you can have 3 levels: •
noinline
doesn't inline the lambda at all, so you can pass it around, store it in variables, use it in nested scopes etc. but you cannot use non-local returns (because it's not inlined in the call site so it wouldn't make sense). •
crossinline
is inlined, but because it can be inlined in nested contexts you have to give up non-local returns (so you don't mess up the control flow in the nested functions that will call that lambda) • regular inline: you can use non-local returns on the call site, but on the flip side you cannot nest it in other contexts inside the inline function body
Essentially when you inline stuff you cannot have non-local returns in nested contexts because that would mess up the control flow. So you either don't use your lambda argument in nested contexts (regular inline), or you give up non-local returns (
crossinline
)
🙌 1
1
t
inline: can return cannot be used in other scope noinline: cannot return can be used in other scope crossinline: cannot return can be used in other scope with crossinline: lose return ability from inline gain scope ability from noinline
💯 1
Thank you so much, sir. I get it now
j
One note you could add to your differences table above is that the difference between noinline and crossinline is, well, that the former is not inlined 🙂 This means for instance that with
noinline
you can assign the lambda argument to a variable, which you cannot do with an inline lambda.
Copy code
inline fun test(callback: () -> Unit) {
    val x = callback // forbidden
}

inline fun test(noinline callback: () -> Unit) {
    val x = callback // allowed
}
💯 3
t
I was reading this article https://www.baeldung.com/kotlin/crossinline-vs-noinline and it does not mention variable assignment at all. So it's nice that you notice that special detail. Thank you for the heads up.