Kotlin - Illegal usage of inline parameter callback


#1

I’m converting my function having lambda as parameter into inline function for performance improvement.

I have list of lambda of type MutableList<(Authenticate) -> Unit> variable as data member in class. When I try to adding lambda parameter into the list.

Kotlin compiler says:
Illegal usage of inline parameter callback

Here is the code

// Some code skipped
object Odoo {

    val pendingAuthenticateCallbacks = mutableListOf<(Authenticate) -> Unit>()

    inline fun authenticate(
        login: String, password: String, database: String,
        quick: Boolean = false, crossinline callback: Authenticate.() -> Unit
    ) {
        // Following statement has error saying
        // Illegal usage of inline parameter callback. add 'noinline' modifier to parameter declaration.
        pendingAuthenticateCallbacks += callback
        // Error in above statement

        if (pendingAuthenticateCallbacks.size == 1) {
            // Retrofit2 Object boxing code skipped
            val call = request.authenticate(requestBody)
            call.enqueue(object : Callback<Authenticate> {
                override fun onFailure(call: Call<Authenticate>, t: Throwable) {
                    (pendingAuthenticateCallbacks.size - 1 downTo 0)
                            .map { pendingAuthenticateCallbacks.removeAt(it) }
                            .forEach {
                                it(Authenticate(httpError = HttpError(
                                        Int.MAX_VALUE,
                                        t.message!!
                                )))
                            }
                }

                override fun onResponse(call: Call<Authenticate>, response: Response<Authenticate>) {
                    (pendingAuthenticateCallbacks.size - 1 downTo 0)
                            .map { pendingAuthenticateCallbacks.removeAt(it) }
                            .forEach {
                                it(Authenticate(httpError = HttpError(
                                        response.code(),
                                        response.errorBody()!!.string()
                                )))
                            }
                }
            })
        }
    }
}

#2

inline means it will copy the code, instead of putting the lambda in an object.
You are storing the lambda as an object.
Therefor it has to be an object.
add change crossinline to noinline to fix this.

for lambda’s:
Does the lambda needs to be stored as an object -> noinline
Does the lambda only needs to be called inside the function-body -> no inline needed.
Does the lambda needs te be called from another context? -> crossinline

Crossinline disables the usage of the local-return: `
This is neccesary when the lambda can be called outside of the local-context.
You still can use return, but then you have to say that you have to say that it needs to return from the lambda.

https://kotlinlang.org/docs/reference/inline-functions.html

https://android.jlelse.eu/inline-noinline-crossinline-what-do-they-mean-b13f48e113c2