Error hierarchies and Kotlin sealed interfaces
In a previous post, I covered what I consider a pretty useful feature of Kotlin: sealed classes.
These classes can be quite useful when modeling errors in Android apps (and beyond). But they have their limitations. Classes, as you probably know, in Kotlin can only extend a single class. What happens, in the relatively common scenario, where an error belongs to multiple error "categories"?
Enter sealed interfaces. A class can implement multiple interfaces. So if the error "categories" are defined as sealed interfaces, a concreate error can belong to multiple "categories".
sealed interface ExpectedError
sealed interface UserError
data class InvalidUserError(val id: Int): UserError, ExpectedError // 1.
data class InvalidArgumentError(val message: String): ExpectedError
fun handleUserError(error: UserError) { // 2.
TODO()
}
fun handleExpectedError(error:ExpectedError) { // 3.
when(error) {
is InvalidArgumentError -> TODO()
is InvalidUserError -> TODO()
}
}
- A single error can belong to multiple "categories".
- And you can handle the error "category" as a whole or ...
- ... handle each error specifically using the
when
statement.
But what's the benefit over defining a normal interface? Remember that you can define subclasses of sealed classes and interfaces only in the same Kotlin module. This limits the scope where these hierarchies can be extended (i.e. in the same module) and therefore limits the misuse surface.
Although this might seem like a simple feature, it opens the way for defining comprehensive error hierarchies. Hopefully, you can use it to make your codebase a bit tidier and a bit harder to misuse.
Happy coding!