Enums are a common convention in coding languages to prevent coding errors. When coding, enums allow me to restrict the domain in my code to just those predefined enumerated types. In other words, an enumerated type is a data type with a set of named constants representing the type. As an example,
WEST are enumerations of the compass direction type. These are a group of constants where the variations are known at compile time.
By using enums, I can increase compile-time checking and decrease coding errors by passing an invalid type. When the enumerations are predefined, I am restricted to those specific types rather than loosely allowing any constant value. While enums are very helpful in this regard, there are some limitations to an enum and that’s where Kotlin sealed classes come into the picture. I like to think of sealed classes as “super” enums. The “super” aspect comes from two key capabilities:
- Saving state in the subclasses of the sealed class
- Allowing different types of objects inside the subclasses of the sealed class
Let’s say I have a very simple Android application. Depending on some internal logic, I need to display a screen of one of the following states:
- Loading page: loading spinner animation
- Error page: text showing the error message
- Data page: data about my pet seal
For simplicity, I could just create an enum of the three different types and then get the data to be displayed for that status’ page. In this case, each enum is a constant value.
However, what if I wanted to store values inside the enum constants. I could do something like this, but note that the enums are not necessarily “stateful”.
This allows me to relate the specific strings to the enum types, but I need different data content to be associated with the
DATA enum instead of just “Displaying data”. It needs to change based on which seal pet I am showing in the application. Also, I really want different enum types to contain varying types inside of them. The
Loading type doesn’t really need any data inside of it, as it will just be showing a loading animation. The
Error type would need a string to hold the error message which could vary depending on the error. Lastly, the
Data type should hold a
SealPet type with information about the seal’s name, age, and honk type.
This leads us to a sealed type for the seals!
Note that we have no state to store in the
Loading type. Therefore, we can make the class a singleton to avoid unnecessary allocations. In Kotlin, this is done through the object keyword in the class definition. In the code above, you can see we made the
Loading type a singleton with the object Kotlin keyword.
Now I have a nice sealed class with some subclasses of different types that are holding state. I can take advantage of them by using the when expression to set the view appropriate to the screen state. Note that the when expression is exhaustive on the sealed class type and does not require an else branch.
Now I have clean and concise code using a sealed class!