---
title: "sealed-enum: Replacing Enums in Kotlin"
source: "/writing/sealed-enum-replacing-enums-in-kotlin/"
---

Article

# sealed-enum: Replacing Enums in Kotlin

Alex Vanyo

November 2, 2020

_Enums are dead, long live enums!_

This is the origin story for [https://github.com/livefront/sealed-enum](https://github.com/livefront/sealed-enum) , a Kotlin annotation processor for generating enum-like objects from sealed classes of objects. For installation and detailed usage, see the project's documentation, but to learn more about why it exists and how you can replace normal enums, read on!

Sealed classes are one of Kotlin's powerful tools to express hierarchies and precisely enumerate the form that data takes. With the `when` keyword, working with sealed classes can be simple and safe, with no need for an annoying `else` branch. When initially presented, especially for someone coming from a Java background, they appear to be even more powerful enums; indeed, the official Kotlin documentation [¹](#id-0) states that sealed classes

> are in a sense, an extension of enum classes.

Ever since I learned about sealed classes, I've used them constantly. Nesting sealed classes allows expressing complex state in an incredibly powerful way, and serializing and deserializing them is effortless with [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) . Generic sealed classes allow convenient handling for common wrappers, like `State<T>` or`Result<T>`.

Yet with everything that sealed classes can do, I still found myself writing the following code:

For how I was using `ScrollingBehavior`, I could have just as easily made it a sealed class:

With `when`, the code to consume the enum class and the sealed class would be pretty much identical. So why do we need still need enums at all? A sealed class of only objects is strictly a more powerful enum: they are both a static, finite enumeration of something. Just like an enum, the sealed class can have constructor arguments or abstract values, and implement interfaces. However, sealed classes are much more flexible than enum classes: they can extend other classes, have generic type arguments, or be part of a nested sealed class hierarchy.

In the scenario above, I didn't need to deal with the full list of `ScrollingBehavior`s. If I had, the enum class would have been the more convenient approach due to the existence of `ScrollingBehavior.values()`. Accomplishing the same for sealed classes is not as simple. The only built-in way is with `KClass.sealedSubclasses` which works, but requires Kotlin reflection, which can be unacceptably slow at runtime. The alternative is maintaining the list of objects manually [²](#id-1) , which also works, but is error-prone boilerplate -- but boilerplate can be automated away!

Furthermore, there's an opportunity here for improved generic handling, since dealing with enums generically is painful. `enumValuesOf<T>()` works if it is possible to access the enum type in a reified way, but if it isn't, the main option is to pass through the `Class` of the enum for `Class.getEnumConstants`.

`sealed-enum` was born to solve both of these problems, and in-effect make defining actual enum classes obsolete in favor of sealed classes of objects, which I call "sealed enums". Taking inspiration from kotlinx.serialization's `KSerializer` objects, annotating the companion object of a properly structured sealed class `T` with `@GenSealedEnum` will result in a generated implementation of `SealedEnum<T>`. That implementation is an object, which provides the `values` list and `ordinalOf` method, implements `Comparator` based on those ordinals, and also includes `nameOf` and `valueOf` methods:

Together, these methods match all of the features of normal enum classes.

For an example of how this works, let's first add `sealed-enum` as a Gradle dependency to our project:

The `sealed-enum` library consists of two parts: a small runtime library, which defines the annotations and the interfaces, and an annotation processor for `kapt`.

Now that we have the library installed, let's annotate a newly created companion object for the `ScrollingBehavior` sealed class above:

The annotation processor then generates a `ScrollingBehaviorSealedEnum` object, which implements `SealedEnum<ScrollingBehavior>`, as well as extension properties and functions for ease-of-use:

Now, by retrieving `ScrollingBehavior.values`, or by passing the `SealedEnum` object around directly, we have all of the features we want from an enum and get to keep all of the extra power that sealed classes offer.

The runtime library and annotation processor also have built-in tools to specify behavior and provide interoperability.

`@GenSealedEnum` can be configured to specify a traversal order, to switch between in-order, pre-order, post-order and level-order traversal for sealed class hierarchies.

For interoperability, there is built-in functionality for both directions: First, there are methods provided in the runtime library to create a `SealedEnum` object given a normal enum class. Second, `@GenSealedEnum` can be configured to generate an isomorphic enum class that implements all of the interfaces that the sealed enum does via interface delegation. If you need to specify an enum value in an annotation, or provide a true enum class to some other interface, you can easily map between the two representations as needed.

Enum classes are great, but sealed classes with objects can be better. By generating the remaining boilerplate to fill in the gaps, you too can upgrade your enums to sealed enums, and never write a normal enum class ever again.

_Alex works at_ [_Livefront_](https://livefront.com/) _, where we write code to test code-writing code._

¹: [^](#id-2) [https://kotlinlang.org/docs/reference/sealed-classes.html](https://kotlinlang.org/docs/reference/sealed-classes.html)

²: [^](http://ff40) This approach matches the result of this discussion: [https://discuss.kotlinlang.org/t/list-of-sealed-class-objects/10087](https://discuss.kotlinlang.org/t/list-of-sealed-class-objects/10087/3)

-   Alex Vanyo

    Software Engineer

    Alex Vanyo

### Tags

[Digital Engineering](/insights/all/?topic=digital-engineering) [Mobile Apps](/insights/all/?topic=mobile-apps)

### Share

-   Copied

## View these next.

[See all](/insights/all/?type=writing)

-   [

    Article

    How To Sabotage Your Project Using Inconsistency

    Collin Flynn

    ](/writing/how-to-sabotage-your-project-using-inconsistency/)
-   [

    Article

    Unit Testing race conditions by creating chaos (Swift)

    Sean Berry

    ](/writing/unit-testing-race-conditions-by-creating-chaos-swift/)
-   [

    Article

    UIApplicationDelegate call sequence reference

    Sean Berry

    ](/writing/uiapplicationdelegate-call-sequence-reference/)
