Contrast `return`, `return@forEach`, and `return@label` inside a lambda. When do you use each?
answer
- Bare return = exit enclosing function
- return@forEach = continue-like, exit one lambda call
- Implicit label = the HOF's name
- Explicit label name@ for nested lambdas
- return@map x supplies the element's mapped value
basics
~20 sPlain return exits the whole surrounding function. return@forEach exits only the current lambda call, like skipping to the next item. A custom return@myLabel does the same but uses a label you defined, which is handy when lambdas are nested.
solid answer
~40 sA bare `return` is a non-local return: it exits the enclosing function (only legal in inline HOFs). `return@forEach` is a **local labelled return** using the *implicit label* equal to the called function's name; it returns from just that lambda invocation, behaving like `continue` for `forEach`. You can also attach an **explicit label** to a lambda: `loop@ { ... return@loop }`. Explicit labels are essential when lambdas are nested and the implicit names would be ambiguous or you want to target an outer lambda. Note: returning a value from a labelled lambda return (`return@map x`) supplies that lambda's result, while a bare `return` with the wrong type is a hard error if the enclosing function's type differs. Choosing local vs. non-local is a readability and control-flow decision, not just syntax.
code
kotlin · 5 linesval doubledOrZero = listOf(1, 0, 3).map dbl@{
if (it == 0) return@dbl 0 // explicit label: value for this element
it * 2
}
// doubledOrZero == [2, 0, 6]go deeper
Distinguishes bare return from return@forEach at a basic continue-vs-exit level.
Explains implicit labels, value-yielding local returns in map, and when to add explicit labels.
Handles nested-lambda disambiguation correctly and reasons about readability tradeoffs.
Advises on team conventions for control flow in inline HOFs to keep early-exit logic clear.
## Three forms ### 1. Bare `return` — non-local Exits the **enclosing function**. Legal only inside lambdas of `inline` functions. ```kotlin fun process(xs: List<Int>) { xs.forEach { if (it < 0) return } // leaves process entirely println("all non-negative") } ``` ### 2. `return@functionName` — implicit-label local return Every lambda passed to a function gets an **implicit label** equal to that function's name. `return@forEach` exits only the **current lambda invocation**, so iteration continues — like `continue`. ```kotlin xs.forEach { if (it < 0) return@forEach // skip this one, keep going } ``` For a lambda that produces a value (e.g., `map`), `return@map y` is the value yielded for that element: ```kotlin val r = xs.map { if (it == 0) return@map -1 else it * 2 } ``` ### 3. Explicit label — `label@ { ... return@label }` You can name a lambda with `label@`. This is needed when: - lambdas are **nested** and implicit names collide or you want to target an outer one, - you call the same function twice and need to disambiguate. ```kotlin fun search(grid: List<List<Int>>): Pair<Int,Int>? { grid.forEachIndexed rows@{ r, row -> row.forEachIndexed { c, v -> if (v == 42) return r to c // non-local: exits search if (v < 0) return@rows // skip the rest of THIS row } } return null } ``` Here `return@rows` jumps out of the outer lambda (one whole row), while a bare `return` exits `search`. ## How to choose - **Bare `return`**: you genuinely want to abandon the enclosing function (early exit / found result). - **`return@fn`**: you want loop-style `continue` semantics — skip the current element. - **Explicit label**: nested lambdas where you must precisely pick which lambda to leave. ## Keywords/APIs involved - `inline` (enables the bare form), implicit labels (`@forEach`, `@let`, `@run`), explicit labels (`name@`). - Contrast with loop labels (`outer@ for ...`) which use the same `@` syntax for `break`/`continue`.
- In `list.map { return@map x }`, what does the returned value mean?It is the result produced for the current element in the resulting list — a local return that yields the lambda's value, not a return from the enclosing function.
- When must you use an explicit label instead of the implicit one?When lambdas are nested or the same function appears twice, so the implicit name is ambiguous and you need to target a specific lambda.
saying these in an interview costs you the question
- Treating `return@forEach` as exiting the enclosing function
- Not knowing the implicit label equals the function name
- Believing explicit labels change inline/non-inline rules
- Confusing lambda labels with loop break/continue labels in semantics
- Thinking `return@map x` returns from the outer function