Is it possible to use return inside a Lambda in Kotlin? You might think, "Of course, you can use return, right?" However, not all Lambda expressions in Kotlin allow the use of return.

So, let's explore when it's possible and when it's not.

First, let's understand what a Lambda is.

What is a Lambda Expression?

Lambda was introduced in Java SDK 1.8, bringing significant changes to Java. The introduction of lambda expressions turned Java into both an object-oriented and functional language.

So, how does Wikipedia define lambda expressions?

A lambda expression, also known as a lambda function,
is a concept used in programming to refer to anonymous functions.
- Wikipedia

In simple terms, a lambda expression represents a method as a single "expression." In other words, when written as a lambda expression, a method loses its name and return value, making it an "anonymous function."

Now, how can we represent lambda expressions? Let's consider some examples.

Suppose you have a function that compares two values and returns the greater value. How can you express this function as a lambda expression?

Function for comparing two values

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

Lambda Expression

(a, b) -> if (a > b) a else b

As shown above, you can express it simply as a lambda expression.

Let's explore another example of a traditional coding convention for printing numbers from 0 to 10.

for (i in 0 until 10) {
    println(i)
}

Now, let's see how we can create it using a lambda expression.

(0 until 10).forEach { println(it) }

For those who are new to lambda expressions, traditional coding conventions might seem more readable. However, let's consider a common code used in Android as an example.

Expressing a checkbox's click event using a lambda expression is much simpler.

Traditional Approach

binding.btnCheck.setOnClickListener(object : OnClickListener{
      override fun onClick(p0: View?) {     
	 println("click")
      }
})

The lambda expression approach is more concise.

binding.btnCheck.setOnClickListener {     
   println("click")
}

Lambda expressions can also be used with higher-order functions.

A higher-order function is a function that can take another function as an argument or return it as a result.

Let's consider an example of using a higher-order function. Imagine you need to create a function that adds a date next to a food item when provided with an order. Using a higher-order function, you can express it as follows.

fun addOrderDate(order: (String) -> String): () -> String {
    return { order("2023-05-07") }
}

fun main() {
    val food = "bread"
    val result = addOrderDate { item -> "$item bread" }
    println(result())
}

Lambda expressions can be used as arguments in functions and can also be used as return types. In the example above, we declared a lambda expression as a parameter with one argument, and when calling the function, we used the lambda expression to produce the return value.

Lambda expressions are a powerful feature that enhances code efficiency, especially in repetitive code and with higher-order functions.

In programming languages that support functional programming,
a function is treated as a first-class object when it can be represented as a value
and can be passed as an argument to other functions or returned as a result.
This concept is similar to mathematical functions. 
- Wikipedia

Is All Lambda Return Possible?

Now that we've explored lambda expressions, let's return to the question posed in the post: "Is it possible to return from a Kotlin lambda?"

Unfortunately, Kotlin's documentation restricts the use of return within lambda expressions:

fun foo() {
    ordinaryFunction {
        return // ERROR: cannot make `foo` return here
    }
}

In the example above, attempting to use return to exit a named or anonymous function implemented as a lambda is not allowed. Lambda expressions do not permit the use of return because lambdas cannot return from the enclosing function (foo() in this case).

However, you can use a label to allow return within a lambda:

fun foo() {
    ordinaryFunction look@{
        return@look // OK: label return
    }
}

Another way to enable return within a lambda is to make the named or anonymous function an inline function:

Lambda expressions within inline functions do allow return.

fun foo() {
    inlined {
        return // OK: the lambda is inlined
    }
}

These returns are called "non-local returns." Return statements within inline functions return from the root that encloses the inline function. In other words, return within an inline function can return from foo().

Kotlin provides inline functions, like forEach, that allow the use of return:

fun hasZeros(ints: List<Int>): Boolean {
    ints.forEach {
        if (it == 0) return true // returns from hasZeros
    }
    return false
}

Conclusion

After learning about lambda expressions and how they work in Kotlin, we revisited the question "Is it possible to return from a Kotlin lambda?"

Many developers believe that returning from an anonymous function or lambda expression is possible. Most assume that this is possible when using inline functions like forEach. However, it's essential to understand that return from a lambda expression is limited in Kotlin.

I recommend understanding when and where you can use return within Kotlin lambda expressions, as demonstrated in this post.

Korean documents can be checked here.