Beware of the destructuring behaviour in Kotlin’s data classes
✦ 2023-01-25
Don’t get me wrong, Kotlin’s Data classes are super cool. If you’re not using them already, you really should be. With data classes you get:
- Automatic implementation of
equals
andhashCode
, - A workable
toString
function, - A cool
copy
method for duplicating objects and updating its properties, and - Destructuring syntax through
compotentN
function generation.
It’s that last point, about the destructuring syntax, that I’m a bit weary of. If you’re not already familiar, here’s how destructuring works for Kotlin data classes:
val lientjie = Cat("Lientjie", 2016)
val (name, yearOfBirth) = lientjie
println("$name, born in $yearOfBirth")
// prints "Lientjie, born in 2016"
The order that the data class’s constructor parameters are defined is the order that those compotentN
functions are generated.
What this means is that you can’t add a new constructor parameter to a data class unless either:
- The new parameter is inserted last in the list, or
- You’re very sure that no code depends on the class’s destructuring order
For example, if we were to extend the Cat
class so that it accepted numberOfVaccinations
as the second parameter, we’d introduce a subtle bug. All without a compiler warning.
val lientjie = Cat("Lientjie", 8, 2016)
val (name, yearOfBirth) = lientjie
println("$name, born in $yearOfBirth")
// prints "Lientjie, born in 8" <- eek
I don’t think its a deal-breaker, especially for data classes that don’t leak into your code’s public contract, but certainly something to keep in mind.