Let’s start with a simple definition about sealed classes:

It’s a kind of ADT(Algebraic Data Type), used for representing restricted class hierarchies, also allowing a datatype to be one of a predefined set of types.

In Kotlin context we can also use sealed classes combined with when expression. Allowing compiler to verify all branch statements, making the statement else unnecessary.

An example of that:

sealed class Intention {

class Refresh : Intention()

class LoadMore : Intention()

} fun main(args: Array<String>) {

val intention: Intention = Intention.LoadMore()

val output = when (intention) {

is Intention.Refresh -> "refresh"

is Intention.LoadMore -> "load more"

}

println(output)

}

Maybe you’re asking yourself: “Does the sealed classes have the same behavior as enum classes?” The answer is almost yes.

A great way to explain sealed is comparing both. First, let’s create two simple classes:

// Enum

enum class Directions { TOP, LEFT, RIGHT, BOTTOM } // Sealed

sealed class Intention {

object None : Intention()

object Refresh : Intention()

data class Error(val reason: String) : Intention()

data class LoadContent(val content: List<String>) : Intention()

}

Both have the same behavior as an abstract class, preventing directly instantiation and allowing us to declare abstract methods:

// Enum

enum class Directions {

TOP { override fun direction(x: Int, y: Int) = x to (y - 1) },

LEFT { override fun direction(x: Int, y: Int) = (x - 1) to (y) },

RIGHT { override fun direction(x: Int, y: Int) = (x + 1) to (y) },

BOTTOM { override fun direction(x: Int, y: Int) = x to (y + 1) };

abstract fun direction(x: Int, y: Int): Pair<Int, Int>

} // Sealed

sealed class Intention {

object None : Intention() {

override fun log() { println("none") }

}



object Refresh : Intention() {

override fun log() { println("refresh") }

}



data class Error(val reason: String) : Intention() {

override fun log() { println("error") }

}



data class LoadContent(val content: List<String>) : Intention() {

override fun log() { println("loadContent") }

}



abstract fun log()

}

In addition, enum can have just a single instance, whereas a subclasses of a sealed class can have multiple instances. Important to realize here is what kind of problem you are handling. If you need a constant behavior, so your pick is an enum , otherwise, sealed is your choice.

Extra bullet

Another important thing to notice, is how the compiler handle the checks when we declare a class as sealed :

// FILE: 1.kt

sealed class A {

class B : A() { // B is declared inside A -- ok

class C: A() // C is declared inside A -- ok

}

} class D : A() { // D and A are declared in same file -- ok



class E : A() // E is declared outside A -- error

} // FILE: 2.kt

class F: A() // F and A are declared in different files -- error

source: https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md