Sealed classes help group related types together. Using when with sealed classes ensures you handle all cases, making your code safer and clearer.
Sealed classes with when exhaustive check in Kotlin
sealed class Result { data class Success(val data: String) : Result() data class Error(val error: String) : Result() object Loading : Result() } fun handleResult(result: Result) { when (result) { is Result.Success -> println("Success: ${result.data}") is Result.Error -> println("Error: ${result.error}") Result.Loading -> println("Loading...") } // No else needed because all cases are covered }
Sealed classes restrict subclassing to the same file, so the compiler knows all subclasses.
The when expression is exhaustive if it covers all subclasses, so no else branch is needed.
when expression that covers both cases.sealed class Shape { object Circle : Shape() object Square : Shape() } fun describe(shape: Shape) = when(shape) { Shape.Circle -> "This is a circle" Shape.Square -> "This is a square" }
when handles both types without else.sealed class Response { data class Success(val message: String) : Response() object Failure : Response() } fun printResponse(response: Response) { when(response) { is Response.Success -> println("Success: ${response.message}") Response.Failure -> println("Failure occurred") } }
This program defines a sealed class TrafficLight with three states. The action function uses a when expression to return the correct action for each light. Because all cases are covered, no else is needed. The main function prints the action for the yellow light.
sealed class TrafficLight { object Red : TrafficLight() object Yellow : TrafficLight() object Green : TrafficLight() } fun action(light: TrafficLight) = when(light) { TrafficLight.Red -> "Stop" TrafficLight.Yellow -> "Get Ready" TrafficLight.Green -> "Go" } fun main() { val currentLight = TrafficLight.Yellow println(action(currentLight)) }
If you add a new subclass to the sealed class, the compiler will warn you to update the when expression.
Sealed classes must be declared in the same file as their subclasses.
Using sealed classes with when helps avoid bugs by forcing you to handle all cases.
Sealed classes group related types and restrict subclassing to one file.
when expressions with sealed classes are exhaustive if all subclasses are handled.
This makes your code safer and easier to maintain.
Practice
sealed classes in Kotlin when combined with a when expression?Solution
Step 1: Understand sealed classes restriction
Sealed classes restrict subclassing to the same file, so all subclasses are known at compile time.Step 2: Effect on when expression
This allows thewhenexpression to be exhaustive because the compiler knows all possible subclasses.Final Answer:
Thewhenexpression becomes exhaustive, ensuring all cases are handled. -> Option AQuick Check:
Sealed classes + when = exhaustive check [OK]
- Thinking sealed classes allow subclassing anywhere
- Confusing sealed classes with data classes
- Believing sealed classes auto-generate methods
Solution
Step 1: Recall sealed class declaration syntax
In Kotlin, sealed classes are declared with the keywordsealedfollowed byclassand the class name.Step 2: Check options for correctness
sealed class Shape {} uses correct syntax:sealed class Shape {}. open sealed class Shape {} incorrectly addsopen, which is not allowed. sealed interface Shape {} usessealed interface, which is invalid. final sealed class Shape {} usesfinal sealed class, which is not allowed.Final Answer:
sealed class Shape {} -> Option AQuick Check:
sealed class declaration = sealed class Shape {} [OK]
- Adding 'open' modifier to sealed class
- Trying to declare sealed interfaces (not allowed)
- Using 'final' modifier with sealed class
describe function when called with Shape.Circle(5.0)?
sealed class Shape {
data class Circle(val radius: Double) : Shape()
data class Rectangle(val width: Double, val height: Double) : Shape()
}
fun describe(shape: Shape): String = when(shape) {
is Shape.Circle -> "Circle with radius ${shape.radius}"
is Shape.Rectangle -> "Rectangle with width ${shape.width} and height ${shape.height}"
}Solution
Step 1: Identify the input and matching when branch
The input isShape.Circle(5.0). Thewhenexpression matchesis Shape.Circlebranch.Step 2: Evaluate the returned string
The branch returns the string "Circle with radius 5.0" using the radius property.Final Answer:
Circle with radius 5.0 -> Option DQuick Check:
Input Circle(5.0) returns "Circle with radius 5.0" [OK]
- Confusing Circle with Rectangle output
- Expecting a compilation error due to else missing
- Returning class name instead of formatted string
sealed class Result {
object Success : Result()
object Failure : Result()
}
fun handle(result: Result) = when(result) {
is Result.Success -> "Success"
}Solution
Step 1: Identify the sealed class subclasses
Result has two subclasses: Success and Failure.Step 2: Check when expression branches
The when expression only handles Result.Success, missing Result.Failure branch.Step 3: Understand Kotlin's exhaustiveness check
Since Result is sealed, when must handle all subclasses or have an else branch. Missing Failure causes compilation error.Final Answer:
Compilation error: when expression is not exhaustive; add branch for Result.Failure. -> Option BQuick Check:
Sealed class when must cover all subclasses [OK]
- Assuming runtime error instead of compile error
- Ignoring missing branches in when
- Thinking sealed classes can't have object subclasses
Operation with subclasses Add, Subtract, and Multiply. Write a Kotlin function calculate that takes an Operation and two integers, and returns the result of applying the operation. Which of the following implementations correctly uses an exhaustive when expression?Solution
Step 1: Check all subclasses handled in when
Operation has Add, Subtract, Multiply. fun calculate(op: Operation, a: Int, b: Int): Int = when(op) { is Operation.Add -> a + b is Operation.Subtract -> a - b is Operation.Multiply -> a * b } handles all three explicitly.Step 2: Verify exhaustiveness and correctness
fun calculate(op: Operation, a: Int, b: Int): Int = when(op) { is Operation.Add -> a + b is Operation.Subtract -> a - b is Operation.Multiply -> a * b } covers all subclasses, so when is exhaustive. The other options miss some subclasses or rely on else, which is less clear.Final Answer:
fun calculate(op: Operation, a: Int, b: Int): Int = when(op) { is Operation.Add -> a + b is Operation.Subtract -> a - b is Operation.Multiply -> a * b } -> Option CQuick Check:
All subclasses covered in when = exhaustive [OK]
- Missing some subclasses in when branches
- Using else instead of explicit branches
- Returning wrong default values
Ready to prove it?
Pass the test and this pattern moves unknown
