Destructuring Assignment, Kotlin vs Scala — Part 1/ 2
Most recently, I started learning Scala. Scala is a JVM language. As you’d expect, there are similarities with other JVM languages like Kotlin and Java. And differences here and there.
Both Kotlin and Scala provide a destructuring assignment feature. Destructuring enables extracting values from a data structure. For instance, data classes in Kotlin. This promotes conciseness in code by avoiding repetitive value extractions.
Java has not been left behind. In Java 21, you can deconstruct fields of a java
record
. Find more here.
Each language implements destructuring differently from the other one.
Kotlin’s destructuring declarations allow you to extract fields from an object to a set of variables.
data class Student(val name: String, val studentId: Int, val score: Double)
// Create an object of a Student
val student = Student(name = "Kotlin student", studentId = 91250, score = 99.00)
// Destructuring declaration
val (name, studentId, score) = student
Then you can use variables independently in any way out.
println("Student name is $name")
println("Student Id is $studentId")
println("Student score is $score")
Under the hood, the compiler uses componentN
operator functions to unpack values of an object and assign them to the variables.
The destructive declaration above is compiled to:
val name = student.component1()
val studentId = student.component2()
val score = student.component3()
Kotlin’s destructuring declarations provide a powerful and concise way to extract and assign values from pairs and data classes.
You could make a class support destructuring declarations. By adding componentN
operator function to the class:
class Employee(
val name: String,
val employeeId: String
) {
operator fun component1(): String = name
operator fun component2() : String = employeeId
}
Then deconstruct it like this:
val employee = Employee("Kotlin Employee", "EmployeeA1")
val(employeeName, employeeId) = employee
println("Employee name is $employeeName")
println("EmployeeId is $employeeId")
component2
is used to extract the second element. If you want to extract the third element, you’ll add component3
operator method, and so on.
This is quite intuitive, isn’t it?
Probably, like me, you’re wondering. How would I implement destructuring assignment in Scala?
Scala uses unapply()
method. To understand how the method works, let’s look at extractor objects.
Scala Extractor Objects
Extractor objects are objects used to deconstruct an object in a consice and flexible manner. Every extractor object has unapply()
method. unapply()
method extracts values compacted in an object and returns back the attributes.
For instance, Student
class:
class Student(val name: String, val studentId: Int, val score: Float)
Then StudentCompanion
extractor object looks like this:
object StudentCompanion:
// 1
def apply(name: String, studentId: Int, score: Float) =
new Student(name, studentId, score)
// 2
def unapply(student: Student): Option[(String, Int, Float)] =
Some(student.name, student.studentId, student.score)
apply()
method creates an instance ofStudent
from the parametersname
,studentId
andscore.
unapply()
method deconstructs the student object and returns student’s name, studentId and score.
We can now use destructuring assignment like this:
// Create an object of Student
val student = Student("Scala Student", 91250, 99.00)
// Destructuring assignment
val StudentCompanion(name, studentId, score) = student
// Use the variables indepently
println(s"Student name => $name")
println(s"Student ID => $studentId")
println(s"Student's Score is $score")
This assignment:
val StudentCompanion(name, studentId, score) = student
is compiled to:
val name = StudentCompanion.unapply(student).get._1
val studentId = StudentCompanion.unapply(student).get._2
val score = StudentCompanion.unapply(student).get._3
unapply()
method works if you want to deconstruct values of an object to a set of single-value items. If you want to deconstruct an object to a collection of extracted values you’d use unapplySeq()
method.
class HobbitName(val firstName: String, val lastName: String)
object HobbitCompanion:
def unapplySeq(hobbit: HobbitName): Option[List[String]]= {
Option(List(hobbit.firstName, hobbit.lastName))
}
Then we can deconstruct HobbitName
to a list of its constituent names:
val hobbitName = HobbitName(firstName = "Bilbo", lastName = "Baggins")
val HobbitCompanion(firstName: String, lastName: String) = hobbit
println(s"firstName => $firstName")
println(s"lastname => $lastName")
Case classes
A case class
is used for modelling immutable data. For example, Student
class:
case class Student(name: String, studentId: String, score: Float)
The Scala compiler generates helpful methods like apply
, unapply
, copy
, equals
and hashCode
for each case class
.unapply
method is used in deconstructing respective objects.
To extra values from an object of the Student
class, you’d write code like this:
val student = Student("Bilbo", "Y19BBN", 3.75)
val Student(name, studentId, score ) = student
println(studentId) // prints Y19BBN
Conclusion
Both Kotlin and Scala support destructuring assignement.
Kotlin uses componetN
functions to unpack fields of an object and assign them to individual properties.
Scala on the other hand uses unapply()
method to deconstruct an object. This is most often used in pattern matching and partial functions.
Fun coding! Or There and Back again 😃.