Eduardo
Eduardo

Reputation: 7141

Kotlin: Multiple returns inside a Lambda

I have a function that catches recoverable exceptions and returns a fallback

private fun <T> safely(block: () -> T, fallback: T): T {
    return try {
        block()
    } catch(exc: SomeException) {
        // Log the exception/do some logic
        fallback
    }
}

I want to be able to add this to the public methods of my class e.g.

fun doSomething(): List<String> = safely({
    val list = mutableListOf<String>("Hello")
    fun someCheck1() = false // Some boolean value
    fun someCheck2() = true // Some boolean value
    do {
        if(someCheck2()) {
            return arrayListOf<String>("Hello", "World")
        }
    } while (someCheck1())
    return list
}, arrayListOf<String>())

However I get compiler errors 'return' is not allowed here

Yet if I remove the return then my return in the loop no longer works and it gets highlighted in my IDE with warning the expression is never used

How can I maintain this type of return logic within a Lambda?

Playground Example

Upvotes: 0

Views: 710

Answers (2)

Ilya
Ilya

Reputation: 23174

return arrayListOf<String>("Hello", "World") here tries to return a value from doSomething function rather than from the lambda passed to safely. However, such return is non-local, since it tries to exit from the function that is not on the top of stack, and therefore it is prohibited.

Another option here is to make safely function inline:

inline fun <T> safely(block: () -> T, fallback: T): T { ... }

and then you'll be able to make a non-local return from block lambda function passed to it.

Upvotes: 1

Dat Pham Tat
Dat Pham Tat

Reputation: 1463

Try

fun doSomething(): List<String> = safely(
    {
        val list = mutableListOf<String>("Hello")
        fun someCheck1() = false // Some boolean value
        fun someCheck2() = true // Some boolean value
        do {
            if (someCheck2()) {
                return@safely arrayListOf<String>("Hello", "World")
            }
        } while (someCheck1())
        list
    }
, arrayListOf<String>())

For further reference, check Using return inside a lambda?

Or you can also extract your block into a separate function (i.e. someCheckFunction(): List<String>), and have fun doSomething() = safely({ someCheckFunction() }, arrayListOf()), but I guess you want to maintain lambda code like above.

Upvotes: 2

Related Questions