Is there already a ticket to discuss possibilities...
# announcements
a
Is there already a ticket to discuss possibilities to improve destructuring in Kotlin? I find this to be very very confusing, especially comparing to Javascript:
Copy code
interface Parent {
    val a: String
    val b: String
}

data class Person1(
    override val a: String = "Person1 a",
    override val b: String = "Person1 b"
): Parent

data class Person2(
        override val b: String = "Person2 b",
        override val a: String = "Person2 a"
): Parent

fun main() {
    val person1 = Person1()
    val person2 = Person2()
    
    person1.let {
        val (a, b) = person1
        println("Destructuing person1, a is ${a}, b is ${b}")
	}
    person2.let {
        val (a, b) = person2
        println("Destructuing person2, a is ${a}, b is ${b}")
	}
}
Results in
Copy code
Destructuing person1, a is Person1 a, b is Person1 b
Destructuing person2, a is Person2 b, b is Person2 a
https://pl.kotl.in/sUDuggWbx
So just because order of overrides changed, destructuring now returns wrong variable. And it’s not even possible to destructure from the Parent interface
Comparing to Javascript: myapi.js
Copy code
module.exports.batch = payload => {
  return <http://client.post|client.post>('/batch', payload)
}
Copy code
const { batch: batchApi } = require('myApi')
You can destructure any property and also change it’s name, and it’s not tied to the index of the property, at least not explicetely
d
It's very simple. Destructuring is provided by data class in order of constructor. Having different rules because an interface declares them in a different order is not realistic.
s
You can destructure an interface: Declare
componentXXX
methods/extension-functions on the interface. Destructuring is fragile, as your example shows. There are other situations as well that expose its fragility. Write unit-tests to test your code.
☝️ 1
d
Does that javascript snippet declare a variable called batch or batchApi? Or is the latter a type?
Just saying that a more complicated scheme that is more powerful isn't necessarily better
a
@Dico that’s the only problem if javascript example, not clear what is the variable and what is the value, coming from another place. In that example,
batch
is property that I get from another object, and
batchApi
is my new local variable name that I will be using in this particular module
So far I find destructuring with data classes not very useful because it’s coupled to the index of the property, defined in the constructor. As my example shows, it’s very easy to end up with the wrong value, spotting something like this in the code review would be next to impossible
@streetsofboston can you share some other examples with me?
s
That'll be a bit hard 😀 I'm on vacation and was typing this during a bus trip to visit a glacier 🇳🇴
😄 2
d
Typically I only use it with local/privately used types
k
And try to keep it to easy cases too, when there's absolutely no doubt about the order.
(x, y) = point
for example.
p
I think this is one of the biggest mistake they did when designing Kotlin. This feature should have never made it in its current state. While it's pragmatic it is so error-prone that it should pretty much never be used. I think it was added hastily and should have been implemented as proper named destructuring or not at all.
k
What is it about position that's suddenly so error-prone? We can manage constructors and function calls just fine, and for the confusing cases you can opt-in use parameter names there too.
👍 1
p
1. Order of fields in a class never mattered in the JVM ecosystem. 2. Kotlin lets you use named parameters to avoid messing up argument order so it's dissapointing that it's so unsafe in other places.
k
1. Order of fields? That's not really what it's about: for data classes fields and constructor parameters are exactly the same. 2. If the specific data class you're dealing with has a confusing ordering you can of course use named field access:
Copy code
val x = point.x
👍 1
p
1. I see your point 2. I can, but will my colleague? What about the guy who wrote the app 3 years ago?
j
I used to think order-based destructuring was error-prone. I tend to dislike everything that makes refactoring error-prone, but I never ran into any issue so far. In fact, I always use IntelliJ's signature change refactoring, thus destructuring declarations get properly updated. Moreover, I kinda like the fact that it's not tied to the name now: the name of some field in the class makes sense from the class's point-of-view, but you might want to name it more precisely on usage site to make the purpose of the variable more explicit. This is especially true for generic types like
Pair
, or even custom generic types like:
Copy code
data class ParseResult<T>(
    val data: T, 
    val stats: Stats,
)

fun parseLogs(file: File): ParseResult<List<Log>> = //...

val (logs, logParsingStats) = parseLogs(logFile)
Having to name the logs
data
here would be a downside of name-based destructuring. I usually don't use destructuring that much, though, I have to admit 🙂