sealed enum

An open source Kotlin annotation processor for replacing enum classes with sealed classes of objects.

Why we built it.

In Kotlin, sealed classes are more powerful and more flexible than enums, but enums can still do some things that sealed classes can't. We recognized that a sealed class of objects is strictly more powerful than enums, given a bit of repeated boilerplate code:

            sealed class Alpha {
    object Beta : Alpha()
    object Gamma : Alpha()

    @GenSealedEnum
    companion object
}

println(Beta.ordinal) // 0
println(Beta.name) // "Beta"
println(Alpha.values) // [Alpha$Beta@491cc5c9, Alpha$Gamma@74ad1f1f]
println(Alpha.valueOf("Beta")) // Alpha$Beta@491cc5c9
          

sealed-enum generates that boilerplate code automatically, so we can replace enums and gain all of the benefits of using sealed classes without the tedious and error-prone maintenance of boilerplate.

How it works.

If the companion object of any sealed class of objects is annotated with @GenSealedEnum, sealed-enum will generate code that allows using the sealed class like an enum. Extension properties are generated for the objects (ordinal and name), as well as the sealed class's companion object (values, valueOf). These extension properties are backed by an object implementing SealedEnum, which provides a generic interface that is more convenient that generically handling normal enum classes.

Additional features include specifying the traversal order of sealed class hierarchies, creating a SealedClass object from normal enum classes, and generating isomorphic enum classes for sealed enums.

How to use it.

0) Add dependencies to Gradle via Jitpack

Via kapt:

            plugins {
    kotlin("kapt")
}

repositories {
    maven(url = "https://jitpack.io")
}

dependencies {
    implementation("com.github.livefront.sealed-enum:sealedenum:VERSION")
    kapt("com.github.livefront.sealed-enum:sealedenumprocessor:VERSION")
}
          

Via ksp:

            plugins {
    id("com.google.devtools.ksp") version "1.8.0-1.0.9"
}

repositories {
    maven(url = "https://jitpack.io")
}

dependencies {
    implementation("com.github.livefront.sealed-enum:runtime:0.7.0")
    ksp("com.github.livefront.sealed-enum:ksp:0.7.0")
}
          

Check out the project on Github for the latest version information.

1) Annotate the companion object of a sealed class with @GenSealedEnum

            sealed class Alpha {
    object Beta : Alpha()
    object Gamma : Alpha()

    @GenSealedEnum
    companion object
}
          

Use the generated extension methods:

            println(Beta.ordinal) // 0

println(Alpha.values) // [Alpha$Beta@491cc5c9, Alpha$Gamma@74ad1f1f]
          

The SealedEnum implementation can be retrieved with Alpha.sealedEnum, and backs the other extensions properties and methods:

                object AlphaSealedEnum : SealedEnum<Alpha> {
    override val values: List<Alpha> = listOf(
        Alpha.Beta,
        Alpha.Gamma
    )

    override fun ordinalOf(obj: Alpha): Int = when (obj) {
        Alpha.Beta -> 0
        Alpha.Gamma -> 1
    }

    override fun nameOf(obj: AlphaSealedEnum): String = when (obj) {
        Alpha.Beta -> "Alpha_Beta"
        Alpha.Gamma -> "Alpha_Gamma"
    }

    override fun valueOf(name: String): AlphaSealedEnum = when (name) {
        "Alpha_Beta" -> Alpha.Beta
        "Alpha_Gamma" -> Alpha.Gamma
        else -> throw IllegalArgumentException("""No sealed enum constant $name""")
    }
}
              

Check out the project on Github for more detailed usage instructions.

Built by Livefront.

Livefront is a digital product consultancy. We're trusted by some of the world's most admired companies to drive strategy, design, and engineering for their core digital experiences. They partner with us to move faster, think bigger, and design products people love.

Learn more