When enums have superpowers (Kotlin)

Thomas Sattlecker
Making Mimo
Published in
4 min readMar 13, 2018

At Mimo, we have a weekly Show & Tell meeting where every team presents what they have worked on last week, and afterward, there is room to share something that you’ve recently learned or that you are passionate about. I created the following post after talking about “When enums have superpowers” at Mimo because I guess this could be interesting for more developers. This is the Kotlin version. You can also find a Swift version of this post here.

This is the second post in the series When enums have superpowers.

I know that there are multiple solutions for this. But the example should demonstrate how you can use sealed classes.

Let’s assume

we have a learning app with the following entities.

  • A Lesson is the smallest entity containing a single topic.
  • A Chapter contains a list of Lesson entities.
  • A Tutorial contains a list of Chapter entities.
  • A Track contains a list of Tutorial entities.
Track -> Tutorial -> Chapter -> Lesson

For each Lesson we also store if the user finished it. So now we can calculate the progress of a user in a chapter / tutorial / track.

Building a Progress View

We want to create a simple ProgressView which displays a title, the progress in % and a progress bar. And we want the view to work with either a Chapter, Tutorial or Track.

This ProgressView has already a very clear API. We can simply instantiate it with either one of the three classes. Internally though it needs a lot of null checking. If we want the possibility to update the data inside a ProgressView instance we either need to keep its properties public or we need to create getter and setter.

Looks good, so what’s the problem here?

First we should take a look at all the possible states of our ProgressView. Since we have 3 nullable properties any variation where either one, all of them or a few of them are set. But we already know that there must only be 1 actual value. If we call ProgressView(chapter) then tutorial and track must be null.

  1. Allows incorrect state — even though our constructor would only allow creating correct state, as soon as we have setters for updating it gets more complicated and harder to only allow correct state. We have to make a lot of checks to enforce this.
  2. Unclear internal correct state — having 3 nullable properties tells us nothing about the correct and allowed states in the ProgressView. Its far from obvious and it allows for very easy mistakes. We need to use null checks a lot to handle it.
  3. No compiler help — the compiler won’t help us here. If we forget null checks it is our own fault.

Sealed Classes or Enums with superpowers

Kotlin has a language feature called Sealed Classes which I would translate into Enums with superpowers. It allows you to store more complex data in your enum cases. Let’s use this to improve our ProgressView.

We create a sealed class ProgressViewType with 3 different cases: Chapter, Tutorial, Track. The actual values are directly contained in the 3 different cases. Even though the actual usage of the ProgressView is a bit longer we now made sure that only correct state is possible.

What improved

  1. Only correct state is possible — We made sure that the ProgressView can only contain one of the following chapter, tutorial or track. We also made sure that there must be one of them. Compared to the first implementation we can see that neither of chapter / tutorial / track is nullable anymore.
  2. Compiler help — The compiler knows the possible states of the sealed class and it can tell you if you missed a case.
  3. Obvious allowed state — compared to the first implementation we can see the allowed and possible states on first sight. Using sealed classes makes for a very explicit API and data model.

The idea of being able to control which states are possible instead of simply checking the correctness brings a lot of advantages. As developers we make mistakes and limiting ourself to a smaller subset of possible errors will lead to more bugfree products.

This post is heavily inspired by a talk from Richard Feldman. Thanks for that!

--

--

Thomas Sattlecker
Making Mimo

Teaching how to code @getmimo | ☕️ love good espresso ☕️