When lambda parameters must be noinline in Kotlin?
Asked Answered
R

1

5

I often encounter errors in Kotlin inlined functions where lambda parameters must be marked noinline. Other times, lambda parameters seem to work OK. I've read the Kotlin documentation of inline functions, and it seems like this is the operative passage explaining the rule:

Inlinable lambdas can only be called inside the inline functions or passed as inlinable arguments, but noinline ones can be manipulated in any way we like: stored in fields, passed around etc.

I'm having trouble unpacking those concepts. Specifically, I'm not sure I fully understand the things I can't do (including what all is in the "etc.") with an inlined lambda -- in other words, the things that would disqualify it from being inlined. Is there a good reference or more explanation/examples of uses that disqualify a Kotlin lambda parameter from being inlined?

Reactor answered 2/12, 2017 at 6:9 Comment(0)
A
7

It's less of "disqualifying" the lambda from being inlined and more of "this action can't be performed on an inlined lambda."

I kind of answered this here.

Inlined methods are directly inserted into the call site, as are any inlined lambdas.

To reuse my old example,

this roughly results in main here:

fun withLambda(lambda: () -> Unit) {
    lambda()
}

inline fun inlinedLambda(lambda: () -> Unit) {
    lambda()
}

fun main(args: Array<String>) {
    withLambda { println("Hello, world") }
    inlinedLambda { println("Hello, world") }
}

being converted to this:

fun main(args: Array<String>) {
    withLambda { println("Hello, world") }
    println("Hello, world") // <- Directly inserted!
}

What you cannot do with an inlined lambda is treat it like an object.

This means you cannot store it in a field:

val a = lambda // <-- error

or call methods on it:

lambda.toString() // <-- error

because it is not an object.

It can also not be passed as an argument to another function

func(lambda) // <-- error

unless the lambda is marked as crossinline, and the other function's parameter is inline.

This is basically stated by the documentation.

noinline ones can be manipulated in any way we like: stored in fields, passed around etc.

Note that some inline functions may call the lambdas passed to them as parameters ... To indicate that, the lambda parameter needs to be marked with the crossinline modifier:

Think of inlined lambdas as having their code directly inserted into the method. Conceptually they do not actually exist, and "calling" them will just insert their contents into the calling method.

Adkisson answered 2/12, 2017 at 9:19 Comment(1)
For me it is working without crossinline, but yea, all what you mentioned working as descripted inline fun inlined(block: () -> Unit) { println("df") inlined1(block) } inline fun inlined1(block: () -> Unit) { println("7") }Ventris

© 2022 - 2024 — McMap. All rights reserved.