Idiomatic Kotlin: Sealed Classes

Tompee Balauag
Familiar Android
Published in
3 min readJul 6, 2018
Photo by Fabrice Villard on Unsplash

This article is a part of the Idiomatic Kotlin series. The complete list is at the bottom of the article.

In this article we will be talking about Sealed classes and why you should be using them more often.

What is a Sealed class?

Sealing a class is limiting its class hierarchy. When you mark a class as sealed, you can only subclass it from a specified location. This allows you to restrict the subclasses for exhaustive evaluation. It is like an enum on steroids in a sense that enum values are single instances while a derived class of a sealed class can have multiple instances.

Motivation

Consider the following example

Multiple classes can implement the Class inteface because it is unbounded. When you try to check if an object is an instance of the Class interface, you still need to implement the else clause to be exhaustive. This is not a big deal but in most cases, the else clause almost always just return an error and might be unreachable anyways. Another thing is that whenever another class implements the Class interface, the compiler will not be notified about it so if you happen to forgot to update your when statement, it will go to default.

How to create a sealed class

Creating a sealed class is as easy as adding the sealed modifier to the class. All derived classes of the sealed class must be nested (Kotlin 1.1) or on the same file (beyond Kotlin 1.1).

Sealed class under the hood

Let us investigate how a sealed class looks like in Java. This declaration in Kotlin

translate to Java like this

A sealed class is an abstract class and is public. So far so good. What if we add a derived class?

This translates to

The compiler now creates a private constructor for the sealed class which forbids you from instantiating it outside. Another important thing to note here is the compiler also generates a synthetic constructor with DefaultConstructorMarker parameter. The derived class uses this constructor instead. Now, if there is a public constructor, why can we not use this in Java instead? The answer lies in the DefaultConstructorMarker. It is package-protected class in kotlin.jvm.internal so you cannot use it in a straightforward manner. For some reason, Kotlin JVM is forgiving and allows it, but on other JVM implementations, i cannot guarantee.

How about that compiler support thing you talked about?

Yes that one. Let us try to create a function that will check all subclasses of a sealed class.

Notice that there is no need to add the default clause since the compiler can already figure out that all subclasses of the sealed class has been checked. Trying to remove or add a new subclass will result in this compile error like this one:

Error:(16, 12) Kotlin: 'when' expression must be exhaustive, add necessary 'is Agility' branch or 'else' branch instead

That’s it for the sealed class. Check out the other articles in the idiomatic kotlin series. The sample source code for each article can be found here in Github.

  1. Extension Functions
  2. Sealed Classes
  3. Infix Functions
  4. Class Delegation
  5. Local functions
  6. Object and Singleton
  7. Sequences
  8. Lambdas and SAM constructors
  9. Lambdas with Receiver and DSL
  10. Elvis operator
  11. Property Delegates and Lazy
  12. Higher-order functions and Function Types
  13. Inline functions
  14. Lambdas and Control Flows
  15. Reified Parameters
  16. Noinline and Crossinline
  17. Variance
  18. Annotations and Reflection
  19. Annotation Processor and Code Generation

--

--