---
title: "Kotlin Name-Based Destructuring: The Silent Bug Fix Most Devs Missed"
published: true
description: "Kotlin 2.3.20 introduces experimental name-based destructuring for data classes, fixing years of silent position-based bugs. Here's what changed and what to do now."
tags: kotlin, android, kmp, architecture
canonical_url: https://blog.mvpfactory.co/kotlin-name-based-destructuring-silent-bug-fix
---
## What You'll Learn
In this walkthrough, I'll show you a bug pattern that has silently shipped to production in countless Kotlin codebases — and the new language feature that eliminates it. We'll cover Kotlin's position-based destructuring problem, the experimental name-based destructuring syntax in Kotlin 2.3.20, and exactly what you should do in your codebase today.
## Prerequisites
- A Kotlin project (Android, KMP, or server-side)
- Familiarity with data classes and destructuring declarations
- Kotlin 2.3.20+ if you want to try the experimental syntax
## Step 1: Understand the Landmine in Your Code
Let me show you a pattern I use in every project — and the bug hiding inside it.
kotlin
data class User(val name: String, val email: String)
val (name, email) = getUser()
This works. Now imagine a teammate refactors the data class during a PR:
kotlin
data class User(val email: String, val name: String)
Now `name` holds the email and `email` holds the name. No compiler error. No warning. It ships clean. Both properties are `String`, so the destructuring maps to `component1()` and `component2()` by position — and silently breaks every call site.
This hits Android and KMP teams especially hard. Data classes are everywhere: API response models, UI state holders, domain entities. A single property reorder corrupts data flow across layers.
## Step 2: See the New Name-Based Syntax
Kotlin 2.3.20 introduces an experimental name-based destructuring that binds to property names instead of positions:
kotlin
val (val mail = email, val username = name) = getUser()
Here, `mail` binds to the `email` property and `username` binds to `name` — regardless of declaration order. You can also match names directly:
kotlin
val (val email, val name) = getUser()
Order in the destructuring expression no longer matters. Reorder properties all you want; the bindings hold.
## Step 3: Enable the Compiler Flag
Since this is experimental, opt in via your build config:
kotlin
// In build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-XXLanguage:+NameBasedDestructuring")
}
}
Enable this in a feature branch and migrate incrementally. Don't adopt it in production modules until it reaches stable status — experimental features can change syntax or semantics between releases.
## Step 4: Protect Your Codebase Today
Here is the minimal setup to get this working safely right now, without any experimental flags:
kotlin
// Instead of this:
val (name, email) = getUser()
// Do this:
val user = getUser()
val name = user.name
val email = user.email
More verbose? Yes. Refactor-proof today? Absolutely.
Destructuring remains perfectly safe where position is inherent and stable:
kotlin
// Maps: key/value is a stable two-element contract
for ((key, value) in map) { ... }
// Pair/Triple: positions are the API
val (first, second) = Pair("a", "b")
The risk is specifically with data classes whose property order is an implementation detail, not a semantic contract.
## Gotchas
**The docs don't mention this, but** the real danger is same-typed adjacent properties. If your data class has `val id: Int` and `val name: String`, a swap would cause a type mismatch the compiler catches. But `val name: String` and `val email: String`? Silent corruption.
**Here's the gotcha that will save you hours:** search your codebase for `val (` patterns on data classes with same-typed properties. These are your highest-risk locations. Replace them with explicit property access now.
**Don't ship experimental features to production.** Play with name-based destructuring in side projects. Watch the Kotlin KEEP and release notes for stabilization. When it lands as stable, migrate — you'll wipe out a whole class of silent bugs in one move.
**Add a lint rule.** Configure detekt or a custom lint check to warn on positional destructuring of data classes where adjacent properties share a type. This is cheap insurance that costs minutes to set up.
| Aspect | Position-based | Name-based (experimental) |
|---|---|---|
| Binding strategy | `component1()`, `component2()` | Property name |
| Resilience to reordering | Breaks silently | Safe |
| Renaming a variable | Always allowed | `val alias = propertyName` syntax |
| Compiler support | Stable since Kotlin 1.0 | Experimental in 2.3.20+ |
| Type safety on reorder | Only if types differ | Always safe |
## Wrapping Up
Position-based destructuring has been a quiet source of production bugs for years. Kotlin 2.3.20's name-based destructuring is the right fix, but it's not stable yet. Audit your destructuring sites, use explicit property access where it matters, add a lint rule, and track the feature for when it graduates. Your future self — debugging a data-swap bug at 2 AM — will thank you.
Top comments (0)