Data, Enum & Sealed Classes
Kotlin has special class kinds that remove boilerplate for common modeling needs.
Data classes
A data class auto-generates equals(), hashCode(), toString(), copy(),
and destructuring components:
data class User(val name: String, val age: Int)
val a = User("Ada", 36)
val b = a.copy(age = 37) // copy with one field changed
println(a) // User(name=Ada, age=36)
println(a == User("Ada", 36)) // true (value equality)
val (name, age) = a // destructuring
Use data classes for values that are defined by their contents (DTOs, results, records).
Enum classes
A fixed set of named constants, which can carry data and methods:
enum class Direction(val degrees: Int) {
NORTH(0), EAST(90), SOUTH(180), WEST(270);
fun opposite(): Direction = when (this) {
NORTH -> SOUTH
SOUTH -> NORTH
EAST -> WEST
WEST -> EAST
}
}
Direction.NORTH.degrees // 0
Direction.valueOf("EAST") // Direction.EAST
Direction.entries // all values
Sealed classes and interfaces
A sealed type has a closed set of subtypes known at compile time — perfect
for modeling “one of these cases”:
sealed interface Shape {
data class Circle(val radius: Double) : Shape
data class Rectangle(val width: Double, val height: Double) : Shape
}
fun area(shape: Shape): Double = when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
// no `else` needed — the compiler knows all cases are covered
}
Because the compiler knows every subtype, a when over a sealed type is
exhaustive without an else. Add a new subtype and the compiler flags every
when you forgot to update — a huge safety win.
Inside each is branch, shape is smart-cast to that subtype, so you can
access shape.radius directly without a manual cast.
Exercises
-
Model a
Resultsealed interface withSuccess(val data: String)andFailure(val error: String), then write awhenthat handles both. -
Using the
Shapetype above, writearea(shape: Shape): Double.Solution
fun area(shape: Shape): Double = when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.height
}
</details>
This solution is in examples/core/part3/ and is tested by CI.
Previous: Inheritance & Interfaces · Next: Objects & Companions