source: pexels.com

Destructuring Assignment, Kotlin vs Scala — Part 1/ 2

Beatrice Kinya

--

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)
  1. apply() method creates an instance of Student from the parameters name , studentId and score.
  2. 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 😃.

--

--

Beatrice Kinya

Android Engineer | Google Developer Expert for Android | Android Author @ Kodeco