skip to content

What is an implicit label in Kotlin, and how do you give a lambda an explicit label to target with a qualified return?

level: middleimportance: should knowfreq 55%

answer

  1. Implicit label = function name
  2. Explicit label: name@ before the {
  3. Explicit label shadows implicit
  4. Needed for nested same-function lambdas
  5. Anonymous fun → bare return is local

basics

~20 s

By default Kotlin names a lambda's label after the function it's passed to, so you can write return@forEach. You can override that by writing your own label before the lambda, like loop@ { ... }, and then use return@loop.

solid answer

~40 s

When a lambda is the argument to a function, Kotlin gives it an **implicit label** equal to that function's name. So inside `list.map { ... }` you can write `return@map value` to return a result from just that lambda. You can also attach an **explicit label** yourself with the `label@` syntax placed right before the lambda's opening brace: `list.forEach myLoop@ { ... return@myLoop }`. An explicit label is required when implicit naming is ambiguous — for instance nested calls to the same function — or when you want a clearer name. Explicit labels shadow the implicit one. The same labeling grammar also drives labeled `break`/`continue` on ordinary loops, but for lambdas only qualified `return@label` applies.

code

kotlin · 8 lines
kotlin
val matrix = listOf(listOf(1, 2), listOf(3, 4))
matrix.forEach row@ {
    it.forEach cell@ {
        if (it == 3) return@row     // skip the rest of THIS row
        print("$it ")
    }
}
// prints: 1 2  (row containing 3 is abandoned at 3)

go deeper

for a junior

Knows return@forEach exists and labels skip a lambda iteration.

for a middle

Explains implicit naming, explicit name@ syntax, and shadowing.

for a senior

Handles nested-lambda ambiguity and contrasts with anonymous-function local returns.

for a principal

Weighs label readability and anonymous functions vs lambdas when designing DSLs and iteration helpers for maintainability.

## Implicit labels Whenever you pass a lambda directly as an argument to a function, Kotlin automatically gives that lambda a **label with the same name as the function**. This is the *implicit label*. ```kotlin listOf(1, 2, 3).map { if (it == 2) return@map 0 // implicit @map it * 10 } // result: [10, 0, 30] ``` For a value-producing lambda like `map`, `return@map x` makes `x` the value this iteration contributes. ## Explicit labels You can override the implicit name by attaching your own label with the `name@` syntax immediately **before** the lambda's `{`: ```kotlin listOf(1, 2, 3).forEach outer@ { if (it == 2) return@outer // skip element 2 println(it) } ``` An explicit label **shadows** the implicit one — once you write `outer@`, `return@forEach` is no longer available there; you use `return@outer`. ## When you need an explicit label Nesting two lambdas from the *same* function makes the implicit label ambiguous: ```kotlin outer.forEach o@ { inner.forEach i@ { if (cond) return@o // jump out of the inner lambda back to outer } } ``` Without labels, `return@forEach` would only resolve to the **innermost** `forEach`. Explicit labels `o@`/`i@` let you choose which lambda to return from. ## Anonymous functions: a label-free alternative An anonymous function `fun(x: Int): Boolean { ... }` lets a bare `return` return from the anonymous function itself, with no label needed — a different way to get local-return semantics: ```kotlin listOf(1, 2, 3).forEach(fun(value) { if (value == 2) return // returns from the anonymous fun, not the outer one println(value) }) ``` ## Key terms - **Implicit label**: auto-name = the called function's name (`@map`, `@forEach`). - **Explicit label**: a user-given `name@` placed before the lambda brace. - **Shadowing**: an explicit label hides the implicit one for that lambda. - **Anonymous function**: `fun(...) { ... }` literal whose bare `return` is local.

  • If you write `forEach myLabel@ { ... }`, can you still use `return@forEach` inside it?
    No. The explicit label `myLabel@` shadows the implicit one, so only `return@myLabel` is valid for that lambda.
  • How does an anonymous function change return semantics compared to a lambda?
    Inside an anonymous function, a bare `return` returns from the anonymous function itself (local), so you don't need a label and you don't get non-local return behavior.

saying these in an interview costs you the question

  • Believing you must always write the label explicitly
  • Placing the label after the brace instead of before it
  • Thinking implicit and explicit labels can both be used on the same lambda
  • Not recognizing nested same-function lambdas need explicit labels
  • Confusing label syntax `name@` with annotation syntax `@name`

context