6 Things you need to know before using Destructuring in Kotlin.
too much de-structuring sweetness will hurt your tooth!
Featured on :
|
|
|
---|

Destructuring is an easier way take out data from your objects. Basically
//class
data class Person(val name:String,val age:Int)
//instantiate
val person = Person("chetan", 25)
//access
val (name,age) = developer
So, now you know another way to initial you variables ! Wow hurray! TheEnd !..
Well wait no! Don't use it just Yet. Destructuring thou comes in handy its has its own quirks and limitations lets go through them one by one.
Gotcha #1 : Missing component 🕵🏻♂️
data class Items(val one: String, val two: String)
val items= Items("1","2")
val (one, two, three) = items
// boom! compile time error, type Items must have a 'component3()' function
if your familiar with Javascript you would have guessed the code should have worked, we would have got third as “null”, well in case of Kotlin something equivalent like “Unit”, “Nothing” or “String?” etc but here we get an error of “component3()” function? what is that?
Under the Hood! ⚙️
In Javascript, destructuring comes in two forms:
- Positional (for arrays and iterables)
- Name/Structural (for objects).
In Kotlin, things are strongly-typed and thus unlike Javascript, which uses key-value/map-like encapsulation, there are full-encapsulation rules for objects. Hence accessing the object by name isn’t applicable unless your using Reflection which is slow and inefficient. Consequently, to support de-structuring, Kotlin team opted for limited use to only positional de-structuring for all use-case.
//example
data class Items(val one: String, val two: String)
val items= Items("1","2")
val (one, two) = items
//converts to
val one = items.component1
val one = items.component2
// means a getter function/operator/field is already present in those
// class which automatically popluates these fields
// What the creators of Kotlin did was actually implement
// 5 extension functions on many of the classes in the
// Collections.kt library that we commonly use.
operator fun <T> List<T>.component1(): T
operator fun <T> List<T>.component2(): T
operator fun <T> List<T>.component3(): T
operator fun <T> List<T>.component4(): T
operator fun <T> List<T>.component5(): T
Gotcha #2 : how to do it in a non-data class? 🧐
So the second problem is related to the first one itself these extensions only exist in the data class, so in case of normal class you need to create these function yourself.
//non data class destructuring
class Items(val one:Int,val two:Int,val three:Int){
...
}
val (o,t,th)= item // create member function component1()...and so on
// manually declare componentN in class
class Items(val one:Int,val two:Int,val three:Int){
operator fun component1(): Int = one
operator fun component2(): Int = two
operator fun component3(): Int = three
}
val (o,t,th)= item // no error
Gotcha #3 : Unpack All 📂
If we require second member of the object we still need to destructure all members object or atleast to the position we require
data class Items(val one:Int, val two:Int, val three:Int)
val items = Items(1,2,3)
val (no1, required, no2)= items
// even if we require "required" paramter we still need to destructure all
//best practice for destructure of unused variables
val (_,requiredOnlyThis,_)= items
Enjoying the Post?
a clap is much appreciated if you enjoyed. No sign up or cost associated :)
If you want to support my content do consider dropping a tip/coffee/donation💰
Gotcha #4 : Reusing/mutable variables 🔃
you can declare them "var" for reusability but cannot use them again for destructuring.
var (one,two)= Items(1,2,3)
// one = 1
// two = 2
one = 5
// one = 5
(one,two)= Items(5,6,3) // error
Gotcha #5 : No support for default values 🤲
default values not supported for default params while unpacking.
var (one,two = 5)= Items(1,2,3) // complie time error
Gotcha #6: Major Deal Breaker ❌
Using positional data for representing a class, is not a good way for accessing its parameter, it doesn't provide any type/name check method to Android Studio/Lint to figure out if any refactoring is been done on the class and the points of destructing are also required to be refactored! i.e Ordering is part of the API contract! if you change your data class constructor arg reordering it will break.
data class Author(
val name: String,
val email: String,
val blog:String
)
val chetan = Author(
"ch8n",
"dev.ch8n@gamil.com",
"ch8n2@twitter"
)
//destructing
val (name,email,twitter) = chetan
//Later due to some reason
data class ContactMe(
val email: String,
val name: String, // rearranged params
val twitter: String
)
val (name,email,twitter) = chetan
// it will compile but now values of name and email is swapped
That's all fokes 🐰🥕 ! See ya again in next post .. Happy Hacking 💻 .
Enjoying the Post?
a clap is much appreciated if you enjoyed. No sign up or cost associated :)
If you want to support my content do consider dropping a tip/coffee/donation💰
Update#1 : now you know the limitations positional destructing possess, a valid question to ask is when? and where? should we use destructing, those details and a sneaky little trick that I figured out to overcome positional refactoring issues are shared in the post below. see you on the other side👽.
