Which one should you choose?

Kotlin sealed class VS sealed interface

Michal Ankiersztajn
3 min readJul 10, 2024

For those who want a short answer, use a sealed interface over a sealed class whenever possible. For the rest of you who want to get into more details:

1. Sealed keyword

What does sealed keyword do?

  • It limits the inheritance/implementation access to the package and module defined.
  • All subclasses are known at compile time.

2. sealed class

They’re in Kotlin longer than sealed interface hence, they’re more commonly used.

How do they work? Think of them as an open class limited to a package. There are many valid use cases where you would want to limit yourself to inheriting from a single class only or leverage the use of init and constructors , this is when you want to use a sealed class

Here’s an example that uses these:

sealed class Animal(
val name: String,
val age: Int,
) {
// init and secondary constructor are unique to sealed classes
// and cannot be used in sealed interfaces
init {
println("Creating $name")
}

constructor(age: Int) : this(name = "Animal of age $age", age = age)

class OldDog : Animal(age = 16)
}

fun main() {
val oldDog: Animal = Animal.OldDog() // Creating Animal of age 16
}

3. sealed interface

You might not see them often because they’re newer than classes. They’re very similar to sealed class es with these differences:

  • No constructor
  • They work like interfaces; hence, a class can implement multiple sealed interface s.

To be honest, those are all the differences.

Here’s an example of how you would try to reformat the previous sealed class

sealed interface Animal {
val name: String
val age: Int

class OldDog : Animal {
override val age = 16
override val name = "Animal of age $age"

// We can't define sinlge init block
// and need to add it to every subclass
init {
println("Creating $name")
}
}
}

fun main() {
val oldDog: Animal = Animal.OldDog() // Creating Animal of age 16
}

sealed interface — has some limitations, but these limitations are usually what we want. It’s rather rare to need secondary constructors or want a shared init block for all of the subclasses. Moreover, these often introduce additional complexity, which makes the system harder to understand.

4. Which one should you choose?

In general, the best practice is to use sealed interface whenever possible. In most situations, sealed classe can be avoided, and unless you need it to be a class (such as using a constructor) then go for the interface instead.

When working in an existing codebase, you most likely will see sealed class in use because they’re much more popular than sealed interface (probably because sealed interface was introduced later) whenever working in such a case, consider replacing class with an interface !

Thanks for reading! Please clap and follow me if you’ve learned something new! :-)

Based on:

--

--

Michal Ankiersztajn

Android/Kotlin Developer & Applied Computer Science Engineer