Kotlin Sealed Classes

Kotlin Sealed Classes (Deep Explanation)

Sealed classes in Kotlin are used to represent restricted class hierarchies.
They are extremely powerful for state handling, result modeling, and safe polymorphism, especially in Android, backend APIs, and clean architecture.

👉 Think of sealed classes as “controlled inheritance”


1. What is a Sealed Class?

A sealed class:

  • Has a fixed set of subclasses

  • All subclasses are known at compile time

  • Subclasses must be in the same file

sealed class Result

2. Why Use Sealed Classes?

Problems with normal inheritance:

  • Anyone can extend the class

  • when needs else

Sealed classes solve this:

  • ✅ No unknown subclasses

  • ✅ Exhaustive when (no else)

  • ✅ Safer state handling


3. Basic Sealed Class Example

sealed class Result {
class Success(val data: String) : Result()
class Error(val message: String) : Result()
}

Usage:

fun handle(result: Result) {
when (result) {
is Result.Success -> println(result.data)
is Result.Error -> println(result.message)
}
}

✅ No else required


4. Object vs Data Class in Sealed Classes

sealed class UiState {
object Loading : UiState()
data class Success(val data: String) : UiState()
data class Error(val msg: String) : UiState()
}

Use:

  • object → no data (singleton)

  • data class → holds data


5. Sealed Class vs Enum (Very Important)

FeatureSealed ClassEnum
Can hold data✅ Yes❌ No
Multiple instances✅ Yes❌ No
Inheritance✅ Yes❌ No
Best forState & ResultsFixed constants

👉 Enums are limited, sealed classes are powerful


6. Sealed Classes with when (Exhaustiveness)

fun render(state: UiState) {
when (state) {
UiState.Loading -> println("Loading...")
is UiState.Success -> println(state.data)
is UiState.Error -> println(state.msg)
}
}

✔ Compiler forces handling all cases
✔ Safer than if-else


7. Sealed Class + Inheritance Rules

sealed class NetworkResult

class Success : NetworkResult()
class Failure : NetworkResult()

Rules:

  • Subclasses must be in same file

  • Can be class, data class, or object

  • Can have constructors & properties


8. Sealed Class with Abstract Members

sealed class Response {
abstract val code: Int
}

data class Ok(val body: String) : Response() {
override val code = 200
}

object NotFound : Response() {
override val code = 404
}


9. Sealed Interfaces (Kotlin 1.5+)

sealed interface Event

data class Click(val x: Int, val y: Int) : Event
object Close : Event

Difference:

  • Interfaces allow multiple inheritance

  • Classes do not


10. Real Android MVVM Example (Very Common)

sealed class UiState {
object Idle : UiState()
object Loading : UiState()
data class Success(val users: List<String>) : UiState()
data class Error(val error: String) : UiState()
}

ViewModel:

val uiState = MutableStateFlow<UiState>(UiState.Idle)

UI:

when (state) {
UiState.Loading -> showLoading()
is UiState.Success -> showData(state.users)
is UiState.Error -> showError(state.error)
UiState.Idle -> Unit
}

11. Sealed Class + Coroutines + Flow

sealed class ApiResult {
object Loading : ApiResult()
data class Success(val data: String) : ApiResult()
data class Error(val msg: String) : ApiResult()
}
flow {
emit(ApiResult.Loading)
emit(ApiResult.Success("Data"))
}

12. Common Mistakes

❌ Using enum instead of sealed class for state
❌ Adding unnecessary else in when
❌ Creating sealed subclasses in different files
❌ Overusing sealed classes everywhere


13. When to Use Sealed Classes?

✅ UI State
✅ API Result
✅ Navigation Events
✅ Error Modeling
✅ Domain Result Types

❌ Simple constants → use enum
❌ Single value → use object


14. Sealed Class vs Abstract Class

FeatureSealedAbstract
Subclass control✅ Yes❌ No
Exhaustive when✅ Yes❌ No
Extension allowedRestrictedOpen

Final Summary

  • Sealed classes = safe, controlled inheritance

  • Best for state & result modeling

  • Eliminates runtime errors

  • Compiler-enforced correctness

  • Essential for modern Kotlin & Android

You may also like...