Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Kotlin Dictionary
  3. sealed class / sealed interface

sealed class / sealed interface

A sealed class in Kotlin restricts subclasses to the same file (or nested inside the class). Combined with when expressions, the compiler enforces exhaustive checks, making sealed classes ideal for state management and result types.

Syntax

// Define a sealed class
sealed class Result<out T>
data class Success<T>(val data: T) : Result<T>()
data class Error(val message: String) : Result<Nothing>()
object Loading : Result<Nothing>()

// Handle all cases exhaustively with when (no else needed)
fun handle(result: Result<String>) = when (result) {
    is Success -> println("Success: ${result.data}")
    is Error   -> println("Error: ${result.message}")
    is Loading -> println("Loading...")
}

// sealed interface (Kotlin 1.5+)
sealed interface Shape
data class Circle(val radius: Double) : Shape
data class Rectangle(val w: Double, val h: Double) : Shape

Syntax Overview

SyntaxDescription
sealed class NameDefines a class whose subclasses can only exist within the same compilation unit.
sealed interface NameDefines a sealed interface, available in Kotlin 1.5 and later.
is SubclassNameType check used in a when expression. With a sealed class, all cases are covered and else is not required.
object SubclassName : Parent()Defines a stateless subclass as a singleton.

Sample Code

// UI state management pattern
sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String, val code: Int = 0) : UiState<Nothing>()
}

// Simulate a network operation
fun fetchUser(id: Int): UiState<String> = when (id) {
    0 -> UiState.Loading
    in 1..100 -> UiState.Success("User-$id")
    else -> UiState.Error("User not found", 404)
}

// Handle all cases exhaustively with when (compiler verifies coverage)
fun render(state: UiState<String>): String = when (state) {
    is UiState.Loading -> "Loading..."
    is UiState.Success -> "Data: ${state.data}"
    is UiState.Error -> "Error(${state.code}): ${state.message}"
}

// Command pattern using sealed class
sealed class Command
data class Move(val dx: Int, val dy: Int) : Command()
data class Rotate(val degrees: Int) : Command()
object Stop : Command()

fun execute(cmd: Command) {
    when (cmd) {
        is Move -> println("Move: (${cmd.dx}, ${cmd.dy})")
        is Rotate -> println("Rotate: ${cmd.degrees} degrees")
        is Stop -> println("Stop")
    }
}

fun main() {
    // UiState demo
    listOf(0, 1, 999).forEach { id ->
        val state = fetchUser(id)
        println(render(state))
    }

    println()

    // Command pattern demo
    val commands = listOf(Move(10, 5), Rotate(90), Move(-3, 2), Stop)
    commands.forEach { execute(it) }
}

Notes

Because sealed class restricts the possible states at the type level, it is well suited for implementing state machines such as Success/Error/Loading, result types, and algebraic data types (ADTs).

When all subclasses are handled in a when expression, the compiler verifies exhaustiveness. If you add a new subclass and forget to handle it, you get a compile error, which improves maintainability. (Exhaustive checking is active when when is used as an expression.)

For class basics, see class / constructor. For smart casts, see Smart cast / as?.

If you find any errors or copyright issues, please .