Sealed Class in Kotlin

Manuchekhr Tursunov
3 min readMar 31, 2023

--

  1. Introduction to Sealed Class
  • A sealed class is a class that can only be subclassed within the same file where it’s declared
  • Subclasses must be declared within the same file as the sealed class
  • Sealed classes are often used to represent a closed set of classes, such as when defining the different states of a state machine

2. Sealed Class vs. Enum Class

  • Sealed classes are similar to enum classes, but provide more flexibility
  • Enum classes represent a fixed set of values, whereas sealed classes can represent a fixed set of classes with additional data and behavior

3. Creating a Sealed Class

  • To create a sealed class, use the “sealed” keyword before the class declaration
  • Sealed classes can have subclasses declared as normal classes within the same file

Example:

sealed class Result {
data class Success(val data: String) : Result()
data class Failure(val error: Throwable) : Result()
}

4. Using Sealed Class in When Expressions

  • One of the primary uses of sealed classes is with “when” expressions to handle different cases
  • Since sealed classes provide a closed set of subclasses, “when” expressions can be exhaustive and the compiler can ensure all cases are covered

Example:

fun handleResult(result: Result) {
when (result) {
is Result.Success -> {
// handle success case
}
is Result.Failure -> {
// handle failure case
}
}
}

5. Sealed Class with Generics

  • Sealed classes can also be used with generics to provide additional flexibility
  • Sealed classes can also use generics to allow for flexible type parameters in the subclasses
sealed class Result<T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure<T>(val error: Throwable) : Result<T>()
}
sealed class Result<out T> {
data class Success<out T>(val data: T) : Result<T>()
data class Failure(val error: Throwable) : Result<Nothing>()

fun handle(onSuccess: (T) -> Unit, onFailure: (Throwable) -> Unit) {
when (this) {
is Success -> onSuccess(data)
is Failure -> onFailure(error)
}
}
}

6. Sealed Class with Inheritance

  • Sealed classes can also inherit from other sealed classes or regular classes, but all subclasses must still be declared in the same file
sealed class Animal {
sealed class Mammal : Animal() {
data class Cat(val name: String) : Mammal()
data class Dog(val name: String) : Mammal()
}

sealed class Reptile : Animal() {
data class Snake(val length: Double) : Reptile()
data class Lizard(val hasTail: Boolean) : Reptile()
}
}

7. Sealed Class with Common Properties

  • Subclasses of a sealed class can have common properties, which can be accessed from the sealed class

Example:

sealed class Shape {
abstract val name: String

data class Circle(override val name: String, val radius: Double) : Shape()
data class Rectangle(override val name: String, val width: Double, val height: Double) : Shape()

fun describe() {
println("$name has an area of ${calculateArea()}")
}

private fun calculateArea(): Double {
return when (this) {
is Circle -> Math.PI * radius * radius
is Rectangle -> width * height
}
}
}

8. Sealed Class with Interfaces

  • Sealed classes can also implement interfaces, which can provide additional behavior

Example:

sealed class Result : Serializable {
data class Success(val data: String) : Result(), Serializable
data class Failure(val error: Throwable) : Result(), Serializable

fun log() {
when (this) {
is Success -> println("Success: $data")
is Failure -> println("Error: ${error.message}")
}
}
}

9. Sealed Class with Companion Object

  • Sealed classes can also have companion objects, which can provide additional utility methods or constants

Example:

sealed class Color {
data class Red(val value: Int) : Color()
data class Green(val value: Int) : Color()
data class Blue(val value: Int) : Color()

companion object {
val BLACK = Color.Red(0) // we are reusing the Red class for BLACK
val WHITE = Color.Blue(255) // we are reusing the Blue class for WHITE
}
}

10. Sealed Class with Nested Sealed Class

  • Sealed classes can also have nested sealed classes, which can provide additional levels of abstraction or hierarchy

Example:

sealed class Vehicle {
sealed class Car : Vehicle() {
data class Sedan(val model: String) : Car()
data class SUV(val model: String) : Car()
}

sealed class Bike : Vehicle() {
data class Cruiser(val model: String) : Bike()
data class Sport(val model: String) : Bike()
}
}

In summary, sealed classes provide a powerful way to represent a closed set of classes in Kotlin. They can be used to simplify code and make “when” expressions exhaustive.

--

--