Sealed with a class

Kotlin Vocabulary — Sealed Classes

Florina Muntenescu
Mar 3 · 4 min read

Often we need to represent a limited set of possibilities; a web request either succeeds or fails, a User can only be a Pro-User or a standard user.

To model this we could use an enum, but this carries a number of limitations. Enum classes only allow a single instance of each value and can’t encode more information on each type, e.g. an Error case having an associated Exceptionproperty.

You could use an abstract class and a number of extensions but this loses the restricted set of types advantage brought by enums. Sealed classes provide the best of both worlds: the freedom of representation of abstract classes and the restricted set of types of enums. Read on to find out more about sealed classes or, if you prefer a video, check it out here:

The basics of sealed classes

Like abstract classes, sealed classes allow you to represent hierarchies. The child classes can be any type of class: a data class, an object, a regular class or even another sealed class. Unlike abstract classes, you have to define these hierarchies in the same file or as nested classes.

Trying to extend the sealed class outside the file it was defined in yields a compile error:

Forgetting a branch?

Often we want to handle all possible types:

But what if someone adds a new type of Result: InProgress:

Rather than relying on our memory or an IDE search to ensure that all when usages handle the new class the compiler can give us an error if a branch isn’t covered. when, like the if statement, only requires us to cover all options (i.e. to be exhaustive) by producing a compiler error when it’s used as an expression:

When expression must be exhaustive, add necessary ‘is InProgress’ branch or else branch instead

To get this nifty benefit even when we’re using when as a statement, add this helper extension property:

So now, by adding .exhaustive, if a branch is missing, the compiler will give us the same error we saw previously.

IDE auto-complete

As all sub-types of a sealed class are known, the IDE can fill all possible branches of a when statement for us:

This feature really shines with more complex sealed classes hierarchies as the IDE can recognise all branches:

This is the type of functionality that can’t be implemented with abstract classes as the compiler doesn’t know the inheritance hierarchy; therefore the IDE can’t generate the branches.

Under the hood

So what makes sealed classes behave as they do? Let’s see what’s going on in the decompiled Java code:

The metadata of the sealed class keeps the list of the child classes, allowing the compiler to use this information where needed.

The Result is implemented as an abstract class with two constructors:

  • A private default constructor
  • A synthetic constructor that can only be used by the Kotlin compiler

So, this means that no other class can directly call the constructor. If we look at the decompiled code of the Success class, we see that it calls through to the synthetic constructor:

Start using sealed classes to model restricted class hierarchies allowing the compiler and IDE to help you avoid type errors.

Android Developers

The official Android Developers publication on Medium

Thanks to Nick Butcher

Florina Muntenescu

Written by

Android Developer Advocate @Google

Android Developers

The official Android Developers publication on Medium

More From Medium

More from Android Developers

More from Android Developers

More from Android Developers

Layout Inspector

More from Android Developers

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade