What is the “Sealed Class” in Kotlin?
In Kotlin, a sealed class is a class that can have a limited number of implementations. Sealed classes are useful when you want to create a restricted class hierarchy, which means that you can only extend the sealed class within the file where it is defined.
Here is an example of how you can define a sealed class in Kotlin:
sealed class Shape {
class Circle(val radius: Double) : Shape()
class Rectangle(val width: Double, val height: Double) : Shape()
class Triangle(val side1: Double, val side2: Double, val side3: Double) : Shape()
}
In this example, the Shape
class is a sealed class, and it has three subclasses: Circle
, Rectangle
, and Triangle
. The Shape
class can only be extended by these three subclasses within the same file. This means that if you try to create a fourth subclass of Shape
in a different file, the code will not compile.
Sealed classes are often used in combination with the when
expression in Kotlin to create a type-safe way of handling different cases. For example:
fun getArea(shape: Shape): Double {
return when(shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
is Shape.Triangle -> {
val s = (shape.side1 + shape.side2 + shape.side3) / 2
Math.sqrt(s * (s - shape.side1) * (s - shape.side2) * (s - shape.side3))
}
}
}
The getArea
function calculates the area of a given Shape
object. The when
expression checks the type of the shape
object and calls the appropriate function to calculate the area based on the type of the object. Because the Shape
class is sealed, the when
expression is exhaustive, which means that it covers all possible cases. This means that the code will not compile if you forget to handle a case in the when
expression.
Different example of a sealed class with when operator in Kotlin:
sealed class Animal {
class Cat : Animal()
class Dog : Animal()
class Fish : Animal()
}
One of the main benefits of using sealed classes is that they allow you to use the when
expression with more safety and conciseness. Because the number of subclasses is known and restricted, the when
expression can be exhaustive, meaning that it covers all possible cases. This allows the compiler to catch mistakes at compile-time and helps to avoid runtime errors.
Here’s an example of using a sealed class with a when
expression:
fun makeNoise(animal: Animal) = when(animal) {
is Animal.Cat -> "meow"
is Animal.Dog -> "woof"
is Animal.Fish -> "blub"
}
Here is an example of a sealed class with data classes in Kotlin:
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
In this example, the Expr
class is a sealed class, and it has three subclasses: Const
, Sum
, and NotANumber
. The Expr
class can only have values that are instances of one of these three subclasses.
You can use a when expression to handle the different cases of a sealed class:
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
In this example, the eval
function takes an instance of the Expr
class as an argument, and uses a when expression to evaluate the expression based on its type. If the expression is a Const
, the function returns the value of the number
field. If the expression is a Sum
, the function recursively evaluates the e1
and e2
fields and returns their sum. If the expression is NotANumber
, the function returns Double.NaN
.
IBRAHIM CAN ERDOGAN