What goes wrong when you nest lambdas that both rely on the implicit `it`, and how should you handle it?
answer
- Inner it shadows outer it
- No it@outer syntax — outer it is unreachable
- Compiles fine; it's a readability/bug hazard
- Fix = name the lambda parameters
- Keep it only for short, flat, single-level lambdas
basics
~10 sIf a lambda inside another lambda both use it, the inner it hides the outer one, so you can't reach the outer value and the code is confusing. Fix it by naming the parameters.
solid answer
~40 sEach single-parameter lambda introduces its own implicit `it`. When you nest them, the **inner** lambda's `it` **shadows** the outer one within the inner body — so inside the nested lambda, `it` always refers to the innermost parameter, and the outer value becomes unreachable through `it`. The compiler allows it (no error), but the code is ambiguous and bug-prone. The idiomatic fix is to give at least the outer lambda — ideally both — an **explicit named parameter**: `outer.forEach { o -> o.items.forEach { i -> use(o, i) } }`. Kotlin's style guidance discourages relying on `it` in nested or long lambdas precisely for this reason. There is no syntax to reach an outer `it` from an inner lambda; naming is the only correct approach.
code
kotlin · 11 lines// Problematic: which `it` is which?
matrix.forEach {
it.forEach { println(it) } // inner it = element; row unreachable
}
// Clear: explicit names
matrix.forEachIndexed { rowIdx, row ->
row.forEachIndexed { colIdx, cell ->
println("[$rowIdx,$colIdx]=$cell")
}
}go deeper
Recognizes that nested it is confusing and that naming parameters helps.
Explains shadowing, that it still compiles, and applies explicit names to fix nested lambdas.
Knows there is no labeled-it, contrasts with this@Label for receivers, and codifies when it is acceptable vs. when to name.
Sets team conventions/lint expectations for lambda parameter naming to prevent shadowing-class bugs at scale.
## The setup Every single-parameter lambda that omits its parameter list gets an implicit parameter named **`it`**. That name is scoped to that lambda's body. Problems arise when lambdas **nest**: ```kotlin rows.forEach { // it = a row it.cells.forEach { // it = a cell — SHADOWS the row's it // here, `it` is the cell; the row is unreachable via it } } ``` ## What 'shadowing' means **Shadowing** is when an inner declaration reuses a name already in scope, hiding the outer one. The inner `it` (the cell) shadows the outer `it` (the row) for the entire inner lambda body. There is **no syntax** like `it@outer` to reach the outer parameter — once shadowed, the outer `it` is inaccessible. ## Why it's a problem - **Ambiguity for readers**: `it` no longer has a single obvious meaning. - **Latent bugs**: you may think `it` is the row when it's actually the cell. - **No compiler help**: this compiles fine; it's a readability/correctness hazard, not a type error. ## The fix — name the parameters Give lambdas explicit names so each value is unambiguous: ```kotlin rows.forEach { row -> row.cells.forEach { cell -> render(row, cell) // both reachable, both clear } } ``` Guidelines: - Always name parameters when lambdas **nest**. - Name them when the lambda body is **long** or the meaning isn't obvious. - It's fine to keep `it` for short, flat, single-level lambdas like `list.map { it.id }`. ## Related receiver note A similar shadowing issue exists with `this` in receiver lambdas (e.g. nested `apply`/`with`), where you disambiguate with **labeled `this@Label`**. For ordinary value parameters there's no labeled `it`, so explicit naming is the tool. ## Summary Nested implicit `it` shadows the outer parameter with no way to reach it; the code still compiles but is unclear and error-prone. Name the parameters (at least the outer one) to fix it.
- Is there a way to reference the outer `it` from inside a nested lambda?No. For value parameters there is no labeled-`it` syntax. Once the inner `it` shadows it, you must have named the outer parameter to use it. So name them up front.
- How is this different from `this` shadowing in receiver lambdas?Receiver lambdas (e.g. nested `apply`) expose `this`, and you can disambiguate with a labeled `this@Outer`. Value-parameter `it` has no such label, so explicit naming is the only fix.
Two people both nicknamed 'it' in the same room: once the second one speaks up, 'it' only means them, and the first is lost in the conversation.
saying these in an interview costs you the question
- Claiming you can write `it@outer` to reach the outer parameter
- Saying nested `it` is a compile error (it isn't)
- Insisting `it` is fine everywhere regardless of nesting
- Confusing parameter `it` with receiver `this` disambiguation
- Not recognizing shadowing as a readability/correctness risk