Using return inside a lambda?

LambdaKotlin

Lambda Problem Overview


In the code below, I want to show my empty views if trips is empty and then return and avoid running the below code, but the compiler says "return is not allowed here".

mainRepo.fetchUpcomingTrips { trips ->
    if (trips.isEmpty()) {
        showEmptyViews()
        return
    }
                
    // run some code if it's not empty
}

Is there a way to return like that?

I know I can just put it in an if else block but I hate writing if else's, it's less understandable/readable in my opinion when there's a few more conditions.

Lambda Solutions


Solution 1 - Lambda

Just use the qualified return syntax: return@fetchUpcomingTrips.

In Kotlin, return inside a lambda means return from the innermost nesting fun (ignoring lambdas), and it is not allowed in lambdas that are not inlined.

The return@label syntax is used to specify the scope to return from. You can use the name of the function the lambda is passed to (fetchUpcomingTrips) as the label:

mainRepo.fetchUpcomingTrips { trips ->
    if (trips.isEmpty()) {
        showEmptyViews()
        return@fetchUpcomingTrips 
    }

    // ...
}

Related:

Solution 2 - Lambda

You can also replace { trips -> with fun(trips) { to form an anonymous function which can use return normally.

Solution 3 - Lambda

Plain return suggests that you return from the function. Since you can't return from the function inside a lambda, the compiler will complain. Instead, you want to return from the lambda, and you have to use a label:

mainRepo.fetchUpcomingTrips { trips ->
    if (trips.isEmpty()) {
        showEmptyViews()
        return@fetchUpcomingTrips
    }

    //run some code if it's not empty
}

Solution 4 - Lambda

The returns allow us to return from an outer function. The most important use case is returning from a lambda expression

A return statement in an anonymous function will return from the anonymous function itself.

fun foo() {
    ints.forEach(fun(value: Int) {
        if (value == 0) return  // local return to the caller of the anonymous fun, i.e. the forEach loop
        print(value)
    })
}

When returning a value, the parser gives preference to the qualified return, i.e.

return@a 1

means "return 1 at label @a" and not "return a labeled expression (@a 1)".

Return By default returns from the nearest enclosing function or anonymous function.

Break Terminates the nearest enclosing loop.

Continue Proceeds to the next step of the nearest enclosing loop.

More details refer Returns and Jumps,Break and Continue Labels

Solution 5 - Lambda

An alternative to the return might be

mainRepo.fetchUpcomingTrips { trips ->
            if (trips.isEmpty())
                showEmptyViews()
            else {
                //run some code if it's not empty
            }
        }

Solution 6 - Lambda

You can Return to Labels:

fun foo() {
    println("begin foo")
    listOf(1, 2, 3, 4, 5).forEach lit@{
        // local return, meaning this function execution will end
        // the forEach will continue to the next element in the loop
        if (it == 3) return@lit
        
        println("- $it")
    }
    println("done with explicit label")
}

Playground demo here.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJozeRiView Question on Stackoverflow
Solution 1 - LambdahotkeyView Answer on Stackoverflow
Solution 2 - LambdaSolomon UckoView Answer on Stackoverflow
Solution 3 - LambdanhaarmanView Answer on Stackoverflow
Solution 4 - LambdasasikumarView Answer on Stackoverflow
Solution 5 - LambdaelectView Answer on Stackoverflow
Solution 6 - LambdaacdcjuniorView Answer on Stackoverflow