Kotlin by Example: Sealed Classes
Representing restricted hierarchies with this sample code demonstrating sealed class declaration for finite subclass sets, object and data class subclasses, exhaustive when expressions without else branch, and state pattern implementation.
Code
// Sealed class defines a closed set of subclasses
sealed class UIState {
object Loading : UIState()
data class Success(val data: String) : UIState()
data class Error(val message: String) : UIState()
}
fun updateUI(state: UIState) {
// 'when' is exhaustive - no 'else' branch needed
val text = when (state) {
is UIState.Loading -> "Please wait..."
is UIState.Success -> "Data: ${state.data}"
is UIState.Error -> "Error: ${state.message}"
}
println(text)
}
fun main() {
val currentState = UIState.Success("User loaded")
updateUI(currentState)
}Explanation
Sealed classes provide a way to define restricted class hierarchies where all direct subclasses must be known at compile time and declared within the same module and package as the sealed class. Prior to Kotlin 1.5, all subclasses had to be in the same file. This feature ensures a finite and predefined set of possible subclasses, making sealed classes ideal for representing states or outcomes like Success, Error, or Loading.
Sealed classes are particularly powerful when combined with when expressions. The compiler can guarantee that all possible cases are covered, eliminating the need for an else branch and leading to more type-safe code. If a new subclass is added later, the compiler will flag all when expressions that need updating, preventing bugs from missing cases.
Subclasses of sealed classes can be object declarations for singleton states without data, data classes for states carrying information, or regular classes for more complex scenarios. This flexibility makes sealed classes more powerful than enums, which can only have single instances per constant. Sealed classes are extensively used in Android development for modeling UI states and result types.
Code Breakdown
sealed class UIState restricts inheritance to known subclasses.object Loading singleton state, data class Success holds data.when (state) exhaustive without else, compiler knows all subclasses.is UIState.Success smart casts state to Success, accessing data property.
