skip to content

How do you skip components you don't need in a destructuring declaration, and what does the underscore actually do?

level: middleimportance: should knowfreq 55%

answer

  1. `_` skips a slot, keeps positions aligned
  2. No componentN() call emitted for `_`
  3. `_` is not a usable variable
  4. Trailing components can just be omitted
  5. Works in for-loops and lambdas too

basics

~10 s

Use an underscore in the position you want to ignore. It tells the compiler to skip that component so the corresponding componentN() is never called and no variable is created.

solid answer

~40 s

Underscore (`_`) is a placeholder for a component you don't want to bind. `val (_, age) = person` skips the first slot and only binds `age` from `component2()`. The underscore is purely positional: it still consumes a slot, so the variables after it line up with the right `componentN()`. Importantly, when you write `_`, the compiler does **not** generate a call to that position's component function at all — useful if calling it would be wasteful or have side effects. You can use multiple underscores. This works in `val`/`var` destructuring, in `for`-loop destructuring, and in destructured lambda parameters. The underscore is not a real variable: you cannot reference it, and it doesn't shadow anything.

code

kotlin · 7 lines
kotlin
data class Triple3(val a: Int, val b: Int, val c: Int)
val (_, b, _) = Triple3(1, 2, 3)
println(b) // 2; component1() and component3() are never called

// stop early instead of trailing underscores:
val (a) = Triple3(10, 20, 30)
println(a) // 10

go deeper

for a junior

Knows _ ignores a value in destructuring.

for a middle

Explains that _ keeps positions aligned and that no component call is emitted for it.

for a senior

Notes the side-effect/perf benefit of skipping the component call and that trailing components can be omitted entirely.

for a principal

Frames _ as intent-revealing code that satisfies static analysis (detekt unused checks) without resorting to suppressions, improving maintainability.

## The problem it solves Destructuring is positional, so if you only want the 2nd or 3rd value you'd still have to name the earlier ones — polluting scope with unused variables that linters flag. ## The underscore placeholder Use `_` in any position you want to ignore: ```kotlin data class Person(val name: String, val age: Int, val city: String) val (_, age, _) = Person("Ada", 36, "London") println(age) // 36 ``` Properties: - **It still occupies a slot.** `_` keeps later variables aligned with the correct `componentN()`. Here `age` is slot 2 → `component2()`. - **No component call is emitted for an underscored slot.** The compiler skips generating `component1()`/`component3()` calls entirely. This matters when a `componentN()` is expensive or has side effects. - **`_` is not a binding.** You cannot read it, and it doesn't shadow an outer `_`. - You may use **several underscores** in one declaration. ## Works everywhere destructuring works ```kotlin // for-loop over a map, ignoring keys for ((_, value) in mapOf("a" to 1)) println(value) // lambda parameter, ignoring the index listOf("x").withIndex().forEach { (_, v) -> println(v) } ``` ## Underscore vs. unused-name Writing a real name like `val (unused, age) = p` still *calls* `component1()` and creates a variable; `_` avoids both the call and the variable. So `_` is the correct, intent-revealing choice and keeps detekt/ktlint quiet about unused variables. ## Trailing components don't need underscores You can simply stop early: `val (name) = person` binds only `component1()` and ignores the rest. You only need `_` to skip a *middle* component while binding a *later* one.

  • Does `val (_, x) = obj` still call `component1()`?
    No. The compiler skips generating the call for an underscored position, which avoids any side effects or cost of that component function.
  • If you only need the first value, must you write `val (a, _) = p`?
    No. You can simply write `val (a) = p`; trailing components are ignored automatically. Underscore is only needed to skip a middle slot before a later bound one.

saying these in an interview costs you the question

  • Thinking `_` is a real variable you can reference
  • Believing `_` still invokes the component function
  • Adding trailing `_` when you could just stop early
  • Using a named placeholder and then suppressing unused-variable warnings

context