thecodex.expert · The Codex Family of Knowledge
Kotlin

Sealed Classes

Add a new subclass to a sealed hierarchy, and every when expression missing that case becomes a compile error immediately — not a bug discovered later in production.

Kotlin 2.1 Enables exhaustive when Last verified:
Canonical Definition

sealed class (or sealed interface) restricts every direct subtype to being defined in the same package and module — the compiler has complete, closed knowledge of every possible subtype at compile time. This is precisely what allows a when expression matching on a sealed type to be verified exhaustive: with every subtype covered, no else branch is required at all, and if a new subtype is added later without updating that when, the compiler immediately flags it as an error rather than silently falling through.

Declaring a sealed hierarchy

Circle, Square, and Triangle are the ONLY classes ever allowed to implement Shape — the compiler knows this completely, since sealed forbids implementations outside this same module.

Kotlinsealed_basics.kt
sealed interface Shape

data class Circle(val radius: Double) : Shape
data class Square(val side: Double) : Shape
data class Triangle(val base: Double, val height: Double) : Shape

Exhaustive when: no else branch needed

Because the compiler knows these three are the ONLY possible Shape subtypes, this when is verified complete — add a fourth shape later without updating this function, and the compiler immediately flags the missing case as an error.

Kotlinexhaustive_when.kt
fun area(shape: Shape): Double = when (shape) {
    is Circle -> Math.PI * shape.radius * shape.radius
    is Square -> shape.side * shape.side
    is Triangle -> 0.5 * shape.base * shape.height
    // no else needed — the compiler VERIFIES these 3 cases are all of them
}

Sealed classes vs enums: state that carries different data

Unlike an enum, where every constant shares the same shape, each sealed subtype can carry genuinely different data — Loading has none, Success carries a value, Error carries a message, all under one type that a when can still handle exhaustively.

Kotlinsealed_result.kt
sealed class UiState
object Loading : UiState()
data class Success(val data: String) : UiState()
data class Error(val message: String) : UiState()

fun render(state: UiState) = when (state) {
    is Loading -> println("Loading...")
    is Success -> println("Data: ${state.data}")
    is Error -> println("Error: ${state.message}")
}

Sources

1
JetBrains. Kotlin Documentation, "Sealed classes and interfaces," kotlinlang.org/docs/sealed-classes.html.