๐ŸŽ“ A1Learner
๐Ÿ”
0 of 37 lessons completed

Kotlin Sealed Classes

A sealed class restricts which classes can inherit from it. Every direct subclass sits in the same file as the sealed class.

A sealed family of shapes

Shape has three subclasses in the same file. The when covers Circle, Square, and Origin, so it needs no else branch.

sealed class Shape
data class Circle(val radius: Int) : Shape()
data class Square(val side: Int) : Shape()
class Origin : Shape()
fun describe(shape: Shape): String = when (shape) {
    is Circle -> "Circle with radius ${shape.radius}"
    is Square -> "Square with side ${shape.side}"
    is Origin -> "Origin point"
}
fun main() {
    println(describe(Circle(3)))
    println(describe(Square(4)))
    println(describe(Origin()))
}

A result family with two cases

Success carries a loaded value and Failure carries a message. The when reads the carried value from each case after the is check.

sealed class ApiResult
data class Success(val value: Int) : ApiResult()
data class Failure(val message: String) : ApiResult()
fun show(result: ApiResult): String = when (result) {
    is Success -> "Loaded ${result.value}"
    is Failure -> "Failed with ${result.message}"
}
fun main() {
    println(show(Success(42)))
    println(show(Failure("no network")))
}

Creating the sealed class itself fails

This program tries to create Shape directly instead of creating a subclass. The compiler refuses the call.

sealed class Shape
data class Circle(val radius: Int) : Shape()
fun main() {
    val shape = Shape()
    println(shape)
}

Example

sealed class Signal
class Stop : Signal()
class Go : Signal()
data class Caution(val seconds: Int) : Signal()
fun action(signal: Signal): String = when (signal) {
    is Stop -> "Wait here"
    is Go -> "Move now"
    is Caution -> "Slow down for ${signal.seconds} seconds"
}
fun main() {
    println(action(Stop()))
    println(action(Go()))
    println(action(Caution(5)))
}

Key points

  • A subclass of a sealed class must sit in the same file.
  • A when expression over a sealed type can cover every subclass.
  • An exhaustive when over a sealed type needs no else branch.
  • The compiler proves the when is complete because the full set of subclasses is known.
  • A data class subclass carries values for one case.
  • A plain class subclass can stand for one case that carries no values.

In this example, Signal is a sealed class with two plain subclasses and one data class subclass. The when in action covers all three cases, so the function needs no else branch. The Caution case carries a number of seconds, and the branch reads that value after the is check.

Note

A sealed class itself cannot be created directly because its constructor is protected.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Kotlin Playground

Exercise

Why can a when over a sealed class leave out the else branch?