Destructuring declaration is a Kotlin feature that lets you decompose an object into multiple variables in a single expression. The val (name, age) = user construct simultaneously declares two variables, assigning them values from the object’s components. According to the Kotlin documentation (2026), destructuring reduces code volume when working with data classes by 30–50%. Destructuring declaration makes code more concise and readable.
Key Takeaways
val (a, b) = obj for decomposing an object into variablesDestructuring declaration is a Kotlin syntactic construct that allows you to decompose a class instance into multiple variables in a single expression. The left side contains a list of variables in parentheses, the right side contains the object being decomposed. Kotlin automatically calls the corresponding componentN() function for each variable, where N is the ordinal number of the variable in the parentheses.
Destructuring declaration is most commonly used with data classes. The Kotlin compiler automatically generates component1(), component2() and so on for each data class — based on the number of properties in the primary constructor. For regular classes without the data modifier, componentN() are not generated, but they can be defined manually as operator functions with the operator keyword.
Destructuring declaration has become a popular pattern due to its ability to simplify code when working with collections of pairs, function results, and Map iteration. Instead of writing person.firstName, person.lastName, the developer writes val (firstName, lastName) = person. This reduces the number of lines and improves readability, especially in loops and lambdas.
When encountering the val (a, b) = obj construct, the Kotlin compiler generates the following code: val a = obj.component1(); val b = obj.component2(). If the variables are declared with var, var assignments are generated. The type of each variable is inferred from the return type of the corresponding componentN() function. This means that destructuring declaration is fully type-safe and checked at compile time.
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// Destructuring: component1(), component2(), component3()
val (firstName, lastName, age) = person
println("$firstName $lastName, $age years old")
}
In the listing, Person is a data class with three properties. Kotlin generates component1() → firstName, component2() → lastName, component3() → age. The expression val (firstName, lastName, age) = person calls these functions and assigns the results. Importantly: variable names do not need to match property names — the compiler only looks at the order of componentN() and their types. You can decompose only the first N properties, ignoring the rest.
Data classes are the primary candidates for destructuring declaration. Each data class automatically gets componentN() for all properties of the primary constructor. The order of componentN() corresponds to the order of property declarations. This means that when you change the order of fields in a data class, the order of variables in destructuring changes as well — which can lead to subtle bugs.
// Pair destructuring
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// Triple destructuring
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// Map.Entry in loop
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Pair and Triple are standard classes with built-in destructuring for two and three components. Pair is often used as a return type for functions that need to return two related values without creating a separate data class. In a for loop over Map.Entry, the (k, v) = entry construct destructures the key and value via component1() and component2(). This is the standard pattern for iterating over a Map in Kotlin, completely replacing explicit key and value calls.
If some components are not needed during destructuring, Kotlin allows you to replace them with an underscore _. This improves readability — the reader immediately sees that the component is being ignored. Additionally, using _ prevents accidental access to an uninitialized variable: the compiler does not create any variable for _, eliminating warnings about unused variables.
data class Order(
val id: Long,
val customerName: String,
val amount: Double,
val status: String
)
fun process(orders: List<Order>) {
for ((id, _, amount) in orders) {
println("Order $id: $amount")
}
}
In the listing, Order has four properties, but the loop only needs id and amount. The underscore in place of customerName tells the compiler “skip component2()”. Kotlin does not call component2() and does not create a variable for this component. Important: underscores can only be used in destructuring declarations, not in the data class constructor. If multiple consecutive components are skipped, each one gets its own underscore.
For classes without the data modifier, you can manually define componentN() by adding the operator keyword. This allows you to use destructuring declaration with any class, including third-party classes whose source code cannot be modified — simply write an extension function with operator. This approach is especially useful for library classes and Java classes that do not have automatic componentN().
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// For Java class with getters
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("Resolution: ${w}x${h}")
}
In the example, Rect is a regular class without data. Extension functions with operator fun component1() = width and component2() = height add destructuring support. Similarly for java.awt.Dimension: an operator extension on Dimension allows decomposing it into width and height. Limitation: the maximum number of components for destructuring declaration is 5. In theory you can define component6() and above, but Kotlin will not generate the corresponding syntax for 6+ variables in parentheses.
Frequently Asked Questions
Yes, every data class automatically gets componentN() for all properties of the primary constructor. Properties declared in the class body (using constructor parameters without val/var) do not generate componentN().
If val (a, b, c) = obj has an object with only two component functions, the compiler will throw an error. If there are fewer variables (val (a) = pair), Kotlin will only call component1() and ignore component2() — no error will occur.
Yes, Map.Entry supports destructuring: val (key, value) = map.entries.first(). Destructuring does not work on the entire Map at once — only element by element, in a for loop or via an iterator.
Yes, Kotlin supports destructuring in lambda parameters: map.forEach { (k, v) -> ... }. For data classes in lambda parameters, you need to add nested parentheses around the parameter.
Kotlin supports up to 5 variables in a destructuring declaration. If you need to decompose more than five properties, combine them into nested data classes or use Pair/Triple inside a single variable.
Summary
val (a, b) = obj, decomposing an object into multiple variables in a single expressionWe will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also