G. Kh.
G. Kh.

Reputation: 306

What's the point of destructuring declarations in Kotlin?

I have come across the concept called destructuring declarations - when you can return multiple values from a function at once. It seems very convenient, but at the same time it looks like a tricky workaround. Each time when I think about that feature in Java, I understand that it's a hole in my architecture - there should probably be a class then, not just a couple of variables.

What do you think?

Upvotes: 5

Views: 1554

Answers (4)

Agent_L
Agent_L

Reputation: 5421

Destructuring is the most useful when dealing with built-in data structures. Their fields have names making sense in the context of a data structure (handy when you're writing your own hashmap), but completely cryptic when you're dealing with the data contained there (which is 100% of the time, nobody writes their own hashmaps). Eg. Pair with it's first and second or Map.Entry with key and value.

Consider transforming Map values:

    val myMap = mapOf("apples" to 0, "oranges" to 1, "bananas" to 2)

    myMap
        .asIterable()
        .filter { it.value > 0 }
        .sortedBy { it.key.length }
        .joinToString(prefix = "We have ", postfix = " in the warehouse") {
            "{$it.value} of ${it.key}"
        }

To make it readable, you'd have to define intermediate variables:

    myMap
        .asIterable()
        .filter {
            val count = it.value
            count > 0
        }
        .sortedBy {
            val fruit = it.key
            fruit.length
        }
        .joinToString(prefix = "We have ", postfix = " in the warehouse") {
            val count = it.value
            val fruit = it.key
            "$count of $fruit"
        }

Now it's readable, but at what cost?!?

Destructuring makes this cost more beareable:

    myMap
        .asIterable()
        .filter { (fruit, count) -> count > 0 }
        .sortedBy { (fruit, count) -> fruit.length }
        .joinToString(prefix = "We have ", postfix = " in the warehouse") { (fruit, count) ->
            "$count of $fruit"
        }

That's the point.

Upvotes: 0

lmiguelvargasf
lmiguelvargasf

Reputation: 69883

What's the point of destructuring declarations in Kotlin?

Structuring, or construction, is creating an object from values in different variables. Destructuring is the opposite, to extract values into variables from within an existing object.

Part of the Kotlin philosophy is to be concise since the simpler and more concise the code is, the faster you’ll understand what’s going on. Destructuring improves readability which is part of being concise. Compare the following two snippets (let's consider the class Triple)

Without using destructuring

fun getFullName() = Triple("Thomas", "Alva", "Edison")
val result = getFullName()
val first = result.first
val middle = result.second
val last = result.third

Using destructuring

fun getFullName() = Triple("Thomas", "Alva", "Edison")
val (first, middle, last) = getFullName()

It is also possible to take advantage of destructuring to extract key and value from Map's entries.

for ((key, value) in aMap) {
    /* ... */
}

Upvotes: 0

H.Gheisari
H.Gheisari

Reputation: 250

You can also define componentN function as extension for non data classes like this:

operator fun Location.component1() = latitude
operator fun Location.component2() = longitude

and when you want to process on list of locations, you can write this:

for ((lat, lon) in locations) {
    ......
}

Upvotes: 0

hotkey
hotkey

Reputation: 148089

The concept allows having classes that clearly identify a few of their primary properties, the components.

Then you can access these components by using a destructuring declaration, without syntactic noise of accessing the properties.

Compare:

 val point = clickEvent.getPointOnScreen()
 val x = point.xCoordinate
 val y = point.yCoordinate
 // Use `x` and `y` in some calculations

and, assuming that the type has component1 and component2, just:

 val (x, y) = clickEvent.getPointOnScreen()

Basically, it is not necessary to use this sort of syntactic sugar, and the concept itself does not harm any of the abstractions, it only provides a convenient way to access properties of a class instance in some cases when you don't need the instance itself.

Another example is working with map entries, e.g:

for ((key, value) in myMap) { /* ... */ }

There's still a Map.Entry<K, V> behind the (key, value) destructuring, and you can replace it by for (entry in myMap) ..., but usually it's the two properties that you need. This is where destructuring saves you from a little syntactic noise.

Upvotes: 7

Related Questions