What if your program could warn you when you forget to handle a case? Sealed classes make that happen!
Why Sealed classes for restricted hierarchies in Kotlin? - Purpose & Use Cases
Imagine you have a set of related types, like different shapes: Circle, Square, and Triangle. You want to handle each shape differently in your code. Without a clear way to restrict which shapes exist, you might accidentally add unsupported shapes or forget to handle some cases.
Manually managing all possible types is slow and error-prone. You might miss a shape when writing code, causing bugs. Also, adding new shapes anywhere in the code can break existing logic without warning. This makes your program fragile and hard to maintain.
Sealed classes let you define a fixed set of subclasses in one place. This means the compiler knows all possible types and can help you check that you handle every case. It prevents unexpected types from sneaking in, making your code safer and easier to understand.
open class Shape class Circle : Shape() class Square : Shape() // Someone adds Hexagon later fun draw(shape: Shape) { if (shape is Circle) { /*...*/ } else if (shape is Square) { /*...*/ } // No check for Hexagon! }
sealed class Shape { class Circle : Shape() class Square : Shape() } fun draw(shape: Shape) = when(shape) { is Shape.Circle -> { /*...*/ } is Shape.Square -> { /*...*/ } // Compiler warns if a case is missing }
It enables safer and clearer code by restricting and controlling all possible types in a hierarchy.
Think of a traffic light system with fixed states: Red, Yellow, Green. Using sealed classes ensures you only have these states and handle each one properly, avoiding unexpected errors.
Sealed classes restrict which subclasses can exist.
This helps the compiler check all cases are handled.
It makes your code safer, clearer, and easier to maintain.
Practice
sealed classes in Kotlin?Solution
Step 1: Understand sealed class inheritance rules
Sealed classes restrict subclassing to the same file, limiting which classes can extend them.Step 2: Compare options with sealed class purpose
Only To restrict which classes can inherit from it, all in the same file correctly describes this restriction; others describe unrelated features.Final Answer:
To restrict which classes can inherit from it, all in the same file -> Option CQuick Check:
Sealed classes restrict inheritance = A [OK]
- Thinking sealed classes prevent instantiation
- Confusing sealed classes with abstract classes
- Believing sealed classes allow open inheritance
Shape in Kotlin?Solution
Step 1: Recall sealed class declaration syntax
Sealed classes are declared with the keywordsealed classfollowed by the name and body.Step 2: Check each option's correctness
sealed class Shape {} matches the correct syntax. open sealed class Shape {} wrongly combinesopenandsealed. sealed interface Shape {} usessealed interfacewhich is invalid. abstract sealed class Shape {} wrongly combinesabstractandsealed.Final Answer:
sealed class Shape {} -> Option DQuick Check:
Correct sealed class syntax = D [OK]
- Adding 'open' or 'abstract' keywords with sealed
- Using 'sealed interface' instead of 'sealed class'
- Forgetting curly braces after class name
sealed class Result {
data class Success(val data: String) : Result()
object Failure : Result()
}
fun handle(result: Result) = when(result) {
is Result.Success -> "Data: ${result.data}"
is Result.Failure -> "Failed"
}
println(handle(Result.Success("OK")))What is the output when this code runs?
Solution
Step 1: Understand sealed class and when expression
The sealed classResulthas two subclasses:SuccessandFailure. Thewhenexpression covers both cases without else.Step 2: Trace the function call with Success("OK")
The argument isResult.Success("OK"), so the first branch matches, returning "Data: OK".Final Answer:
"Data: OK" -> Option AQuick Check:
Sealed class when covers all cases = "Data: OK" [OK]
- Thinking else branch is required for sealed classes
- Confusing Success and Failure outputs
- Expecting runtime errors from sealed classes
sealed class Animal class Dog : Animal() class Cat : Animal()
Why does this code cause a compilation error?
Solution
Step 1: Recall sealed class subclass rules
Sealed classes restrict subclasses to be declared in the same file.Step 2: Identify the error cause
Dog and Cat are subclasses but declared outside the sealed class file, causing compilation error.Final Answer:
Subclasses Dog and Cat must be declared in the same file as Animal -> Option BQuick Check:
Sealed subclasses must be in same file = B [OK]
- Thinking sealed classes forbid any subclassing
- Believing subclasses must be sealed too
- Confusing sealed with abstract class rules
Admin, Guest, and Member. Which approach correctly uses sealed classes to restrict roles and safely handle all cases?Solution
Step 1: Use sealed class to restrict subclasses
sealed class UserRole { object Admin : UserRole() object Guest : UserRole() object Member : UserRole() } fun describe(role: UserRole) = when(role) { is UserRole.Admin -> "Admin user" is UserRole.Guest -> "Guest user" is UserRole.Member -> "Member user" } declares a sealed class with all subclasses as objects inside the same file, restricting roles properly.Step 2: Check safe handling with exhaustive when
Thewhenexpression covers all subclasses without else, ensuring safe handling.Final Answer:
sealed class UserRole { object Admin : UserRole() object Guest : UserRole() object Member : UserRole() } fun describe(role: UserRole) = when(role) { is UserRole.Admin -> "Admin user" is UserRole.Guest -> "Guest user" is UserRole.Member -> "Member user" } -> Option AQuick Check:
Sealed class + exhaustive when = safe fixed roles [OK]
- Using open or abstract classes without sealing
- Missing exhaustive when branches
- Using sealed interface incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
