The new Certification Class of REST With Spring is out:

>> CHECK OUT THE COURSE

1. Introduction

Simply put, the Kotlin language borrowed a number of concepts from other functional languages to help with writing safer and more readable code. Sealed hierarchies is one of these concepts.

2. What is a Sealed Class?

Sealed Classes allow us to fix type hierarchies and forbid developers from creating new subclasses.

They are useful when you have a very strict inheritance hierarchy, with a specific set of possible subclasses and no others. The compiler guarantees that only classes defined in the same source file as the sealed class are able to inherit from it.

Sealed classes are also implicitly abstract. They should be treated as such throughout the rest of your code, except that nothing else is able to implement them.

Sealed classes can have fields and methods defined in them, including both abstract and implemented functions. This means that you can have a base representation of the class and then adjust it to suit on the subclasses.

3. When to Use Sealed Classes?

Sealed classes are designed to be used when there are a very specific set of possible options for a value, and where each of these options is functionally different – just Algebraic Data Types.

Common use cases might include implementing a State Machine or in Monadic Programming, which is becoming increasingly more popular with the advent of functional programming concepts.

Anytime you have multiple options and they only differ in the meaning of the data, you may be better off using Enum Classes instead.

Anytime you have an unknown number of options, you can not use a sealed class because this will stop you adding options outside of the original source file.

4. Writing Sealed Classes

Let’s start by writing our own sealed class – the good example of such sealed hierarchy is an Optional from Java 8 – which can be either Some or None. 

When implementing this, it makes a lot of sense to restrict the possibility of creating new implementations – the two provided implementations are exhaustive and no one should add their own.

As such, we can implement this:

sealed class Optional<out V> {
    // ...
    abstract fun isPresent(): Boolean
}

data class Some<out V>(val value: V) : Optional<V>() {
    // ...
    override fun isPresent(): Boolean = true
}

class None<out V> : Optional<V>() {
    // ...
    override fun isPresent(): Boolean = false
}

It can now be guaranteed that any time you have an instance of Optional<V>, you actually have either a Some<V> or a None<V>.

In Java 8, the actual implementation looks different because of the absence of sealed classes.

We can then make use of this in our computations:

val result: Optional<String> = divide(1, 0)
println(result.isPresent())
if (result is Some) {
    println(result.value)
}

The first line will either return a Some or a None. We then output whether or not we got a result.

5. Use with When

Kotlin has support for using sealed classes in its when constructs. Because there are always an exact set of possible subclasses, the compiler is able to warn you if any branch is not handled, in exactly the same way that it does for enumerations.

This means that in such situations, there is normally no need for a catch-all handler, which in turn means that adding a new subclass is automatically safe – the compiler will immediately warn you if you haven’t handled it, and you will need to fix such errors before continuing.

The above example can be extended to output either the result or an error depending on the type returned:

val message = when (result) {
    is Some -> "Answer: ${result.value}"
    is None -> "No result"
}
println(message)

If either of the two branches were missing, this would not compile and instead result in an error of:

'when' expression must be exhaustive, add necessary 'else' branch

6. Summary

Sealed classes can be an invaluable tool for your API design toolbox. Allowing a well-known, structured class hierarchy that can only ever be one of an expected set of classes can help remove a whole set of potential error conditions from your code, whilst still making things easy to read and maintain.

As always, code snippets can be found over on GitHub.

Go deeper into building a REST API with Spring:

>> CHECK OUT THE COURSE

Sort by:   newest | oldest | most voted
B. K. Oxley (binkley)
Guest

Are enum classes sealed?

Grzegorz Piwowarek
Editor

Yes – enum behavior follows the “sealed” semantics

wpDiscuz