— Kotlin, Sealed Classes — 1 min read
A sealed class is a special type of class in Kotlin that allows you to define a restricted hierarchy of related classes. Unlike regular classes, sealed classes cannot be instantiated directly. Instead, they are intended to be used as base classes for a set of related classes, which are typically defined as subclasses of the sealed class.
Sealed classes are useful when you want to represent a fixed set of types, where each type has a unique behavior. For example, consider a simple expression evaluator that supports only two types of expressions: literals and binary operations. You can use a sealed class to define these two types of expressions and ensure that no other types of expressions can be created.
1sealed class Expr {2 class Literal(val value: Int) : Expr()3 class BinOp(val left: Expr, val op: String, val right: Expr) : Expr()4}
In the example above, the Expr
class is declared as sealed using the sealed
modifier. This means that only classes defined within the same file as Expr
can inherit from it. The two subclasses of Expr
, Literal
and BinOp
, are defined as inner classes of Expr
.
When you declare a sealed class, Kotlin automatically generates a set of subclasses for it. These subclasses are defined within the same file as the sealed class and must be declared as data
or inner
classes.
Each subclass of a sealed class is a final class, which means that it cannot be further subclassed. This restriction ensures that the set of subclasses is fixed and that no other classes can be added to the hierarchy at a later time.
1sealed class Expr {2 data class Literal(val value: Int) : Expr()3 data class BinOp(val left: Expr, val op: String, val right: Expr) : Expr()4}
In the example above, Literal
and BinOp
are declared as data
classes, which makes them eligible for pattern matching using when
expressions. Pattern matching with sealed classes is very useful because it allows you to exhaustively match on all possible cases without needing a default case.
1fun eval(expr: Expr): Int = when (expr) {2 is Expr.Literal -> expr.value3 is Expr.BinOp -> {4 val left = eval(expr.left)5 val right = eval(expr.right)6 when (expr.op) {7 "+" -> left + right8 "-" -> left - right9 "*" -> left * right10 "/" -> left / right11 else -> throw IllegalArgumentException("Unknown operator: ${expr.op}")12 }13 }14}
The eval
function above demonstrates how pattern matching with sealed classes can be used to evaluate expressions. By handling each possible case explicitly, we ensure that the function is total and that it will not throw an exception at runtime.
Sealed classes are a powerful feature in Kotlin that allow you to define restricted hierarchies of related classes. They are useful when you need to represent a fixed set of types and ensure that no other types can be created. By using sealed classes, you can write more expressive and safer code that is easier to maintain and reason about.