Kotlin Sealed Classes | Android Introduction #27

ibrahimcanerdogan
3 min readJan 22, 2024

--

In this reading, you will explore the concept of using sealed classes to represent restricted hierarchies and the consequences of using sealed classes.

UDEMY COURSE

As explained in a previous module, classes connected in parent-child relationships form hierarchies. For instance, when you have an abstract class Animal, with subclasses Dog and Cat, they are in a relationship one to another, and they form a hierarchy of objects.

abstract class Animal
class Dog : Animal()
class Cat : Animal()

Such a hierarchy is called open, because one can always define another class that inherits from Animal. That makes a lot of sense, there is no limit to the number of animal types. However, this is not true for all the hierarchies. Consider that you try to make a network operation. The result is either a success or a failure. You do not want to allow anyone to define any other subclasses. That is a case for using a sealed modifier instead of abstract.

sealed class Result
class Success(val data: String) : Result()
class Failure(val exception: Throwable) : Result()

A sealed modifier used in front of a class behaves just like abstract, but it also introduces some limitations.

Officially subclasses of a sealed class need to be defined in the same package. What is more important is that a sealed modifier is information to the developer who reads the code — it informs them that this class has a limited number of subclasses known in advance during compilation.

Sealed Classes & When Expressions

There is one important consequence of using sealed classes. You might remember that using when as an expression, you need to specify an else block so that there is always something returned.

fun constructLabel(role: String, name: String): String {
return when (role) {
"ceo" -> "The boss"
"manager" -> "Manager $name"
"worker" -> name
else -> "Unknown role"
}
}

fun main() {
val label = constructLabel("manager", "Leonard")
println(label) // Manager Leonard
}

There are exceptions to this rule. As demonstrated previously, you do not need to specify else if you when expression with an enum class, and you cover all the possible values.

enum class Role {
CEO,
MANAGER,
WORKER
}

fun constructLabel(role: Role, name: String): String {
return when (role) {
CEO -> "The boss"
MANAGER -> "Manager $name"
WORKER -> name
}
}

fun main() {
val label = constructLabel(Role.MANAGER, "Leonard")
println(label) // Manager Leonard
}

Another such exception is when you use when with a sealed class value, and you cover all the possible subtypes. Take a look at the code below. Since it covers all the possible subtypes of Role in a when expression, you do not need to specify an else block. It is possible thanks to the sealed modifier.

sealed class Role
class CeoRole(): Role()
class ManagerRole(val name: String): Role()
class WorkerRole(val name: String): Role()

fun constructLabel(role: Role): String {
return when (role) {
is CeoRole -> "The boss"
is ManagerRole -> "Manager ${role.name}"
is WorkerRole -> role.name
}
}

fun main() {
val label = constructLabel(ManagerRole("Leonard"))
println(label) // Manager Leonard
}

You should now better understand the concept of using sealed classes to represent restricted hierarchies and the consequences of using sealed classes.

İbrahim Can Erdoğan

LINKEDIN

YOUTUBE

UDEMY

GITHUB

--

--

ibrahimcanerdogan
ibrahimcanerdogan

Written by ibrahimcanerdogan

Hi, My name is Ibrahim, I am developing ebebek android app within Ebebek. I publish various articles in the field of programming and self-improvement.

No responses yet