0
0
Kotlinprogramming~15 mins

Sealed classes for restricted hierarchies in Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - Sealed classes for restricted hierarchies
What is it?
Sealed classes in Kotlin are special classes that let you define a restricted set of subclasses. They help you create a fixed hierarchy where all possible types are known at compile time. This means you can control which classes can inherit from the sealed class. It is useful for representing limited choices or states in your program.
Why it matters
Without sealed classes, you might accidentally allow any class to inherit from a base class, making your code less safe and harder to understand. Sealed classes solve this by restricting inheritance, which helps the compiler check your code more thoroughly. This leads to fewer bugs and clearer logic, especially when handling different cases in your program.
Where it fits
Before learning sealed classes, you should understand basic classes and inheritance in Kotlin. After sealed classes, you can explore advanced Kotlin features like data classes, enum classes, and when expressions that work well with sealed classes.
Mental Model
Core Idea
Sealed classes let you define a closed set of subclasses so the compiler knows all possible types in a hierarchy.
Think of it like...
Imagine a locked box that only certain keys can open. Sealed classes are like that box, and only specific keys (subclasses) are allowed to fit inside, no others.
SealedClass
  ├─ SubclassA
  ├─ SubclassB
  └─ SubclassC

All subclasses must be inside the same module or file.
Build-Up - 6 Steps
1
FoundationUnderstanding basic class inheritance
🤔
Concept: Learn how classes inherit from other classes in Kotlin.
In Kotlin, a class can inherit from another class using the colon syntax. For example: open class Animal class Dog : Animal() Here, Dog inherits from Animal. This means Dog is a type of Animal.
Result
Dog is recognized as a subtype of Animal, so you can use Dog wherever Animal is expected.
Understanding inheritance is essential because sealed classes build on this idea but add restrictions.
2
FoundationIntroducing sealed classes syntax
🤔
Concept: Learn how to declare a sealed class and its subclasses.
A sealed class is declared with the 'sealed' keyword: sealed class Result class Success(val data: String) : Result() class Failure(val error: Throwable) : Result() All subclasses must be in the same file or module.
Result
The compiler knows that Result can only be Success or Failure (or other subclasses you define here).
Sealed classes restrict inheritance to a known set, enabling safer and clearer code.
3
IntermediateUsing sealed classes with when expressions
🤔Before reading on: do you think the compiler can warn you if you forget to handle a subclass in a when expression? Commit to yes or no.
Concept: Learn how sealed classes improve control flow with exhaustive when expressions.
When you use a sealed class in a when expression, Kotlin knows all subclasses. For example: fun handle(result: Result) = when(result) { is Success -> println("Data: ${result.data}") is Failure -> println("Error: ${result.error}") } If you forget a subclass, the compiler warns you.
Result
You get safer code because you must handle all possible cases.
Knowing that sealed classes enable exhaustive checks helps prevent bugs from missing cases.
4
IntermediateSealed classes vs enum classes
🤔Before reading on: do you think sealed classes and enum classes can represent the same kinds of data? Commit to yes or no.
Concept: Understand the difference and when to use sealed classes or enums.
Enum classes represent fixed sets of constants without extra data: enum class Direction { NORTH, SOUTH, EAST, WEST } Sealed classes can have subclasses with different properties and types: sealed class Shape class Circle(val radius: Double) : Shape() class Rectangle(val width: Double, val height: Double) : Shape() Use enums for simple fixed values, sealed classes for complex hierarchies.
Result
You choose the right tool for your data structure needs.
Recognizing the strengths of sealed classes over enums helps design flexible and safe models.
5
AdvancedSealed interfaces and Kotlin 1.5+ features
🤔Before reading on: do you think sealed interfaces behave exactly like sealed classes? Commit to yes or no.
Concept: Learn about sealed interfaces introduced in Kotlin 1.5 and how they differ from sealed classes.
Kotlin 1.5 introduced sealed interfaces, which allow you to restrict implementations like sealed classes but support multiple inheritance: sealed interface Expr class Const(val number: Double) : Expr class Sum(val e1: Expr, val e2: Expr) : Expr Sealed interfaces can be implemented by classes and other interfaces, offering more flexibility.
Result
You can design restricted hierarchies with interfaces, enabling multiple inheritance safely.
Knowing sealed interfaces expands your toolkit for designing restricted type hierarchies beyond classes.
6
ExpertCompiler checks and bytecode generation
🤔Before reading on: do you think sealed classes generate more runtime overhead than regular classes? Commit to yes or no.
Concept: Understand how the Kotlin compiler enforces sealed class restrictions and how it compiles them to JVM bytecode.
The compiler enforces that all subclasses of a sealed class are known at compile time by requiring them in the same module or file. At runtime, sealed classes compile to abstract classes with final subclasses. There is no extra runtime overhead compared to normal inheritance. Exhaustive when checks are compile-time features only.
Result
Sealed classes provide safety without runtime cost.
Understanding the compile-time enforcement and zero runtime penalty clarifies why sealed classes are both safe and efficient.
Under the Hood
Sealed classes work by restricting subclassing to the same module or file, allowing the compiler to know all possible subclasses. This enables the compiler to perform exhaustive checks in when expressions. Internally, sealed classes compile to abstract classes with final subclasses, so the JVM treats them like normal classes without extra overhead.
Why designed this way?
Sealed classes were designed to improve safety and clarity in representing restricted hierarchies. Before sealed classes, developers used enums or open classes, which lacked flexibility or safety. Restricting subclasses to the same module/file ensures all cases are known, enabling compiler checks and reducing runtime errors.
SealedClass (abstract)
  │
  ├─ SubclassA (final)
  ├─ SubclassB (final)
  └─ SubclassC (final)

Compiler knows all subclasses here → Exhaustive when checks

At runtime, behaves like normal inheritance with no extra overhead
Myth Busters - 4 Common Misconceptions
Quick: Do you think sealed classes allow subclasses anywhere in the project? Commit to yes or no.
Common Belief:Sealed classes can have subclasses anywhere in the project like normal open classes.
Tap to reveal reality
Reality:Sealed classes restrict subclasses to the same module or file, so the compiler knows all subclasses.
Why it matters:If you assume subclasses can be anywhere, you might miss handling some cases, leading to bugs and incomplete logic.
Quick: Do you think sealed classes add runtime overhead compared to normal classes? Commit to yes or no.
Common Belief:Sealed classes add extra runtime cost because of their restrictions.
Tap to reveal reality
Reality:Sealed classes compile to normal abstract classes with final subclasses, so there is no extra runtime overhead.
Why it matters:Believing in extra overhead might discourage using sealed classes, missing out on their safety benefits.
Quick: Do you think sealed classes and enum classes are interchangeable for all use cases? Commit to yes or no.
Common Belief:Sealed classes and enums can be used interchangeably for representing fixed sets of values.
Tap to reveal reality
Reality:Enums represent fixed constants without extra data, while sealed classes can have subclasses with different properties and types.
Why it matters:Using enums when you need complex data can lead to awkward code; using sealed classes for simple constants can be overkill.
Quick: Do you think sealed interfaces behave exactly like sealed classes? Commit to yes or no.
Common Belief:Sealed interfaces are just sealed classes with a different name.
Tap to reveal reality
Reality:Sealed interfaces allow multiple inheritance and can be implemented by classes and interfaces, offering more flexibility than sealed classes.
Why it matters:Confusing them can lead to design mistakes, especially when multiple inheritance is needed.
Expert Zone
1
Sealed subclasses must be in the same module or file, but Kotlin 1.5+ allows subclasses in the same module, not just the same file, increasing flexibility.
2
When expressions with sealed classes are exhaustive only if used as expressions; using them as statements may not trigger compiler warnings.
3
Sealed classes can be combined with data classes to create immutable, type-safe hierarchies that are easy to pattern match.
When NOT to use
Avoid sealed classes when your hierarchy needs to be open for extension by unknown future subclasses, such as plugin systems. Use open classes or interfaces instead. Also, for simple fixed sets without extra data, prefer enum classes for simplicity and better JVM support.
Production Patterns
Sealed classes are widely used in Kotlin for representing UI states, network response results, and algebraic data types. They enable safe and clear handling of different cases with when expressions, reducing bugs in production apps.
Connections
Algebraic Data Types (ADTs)
Sealed classes implement the concept of sum types in ADTs.
Understanding sealed classes helps grasp how programming languages represent choices and variants safely, a core idea in functional programming.
Finite State Machines (FSM)
Sealed classes can model states in FSMs with restricted transitions.
Knowing sealed classes helps design clear and safe state machines by enumerating all possible states explicitly.
Access Control in Security
Sealed classes restrict subclassing like access control restricts resource usage.
Recognizing sealed classes as a form of controlled access deepens understanding of how software enforces boundaries and safety.
Common Pitfalls
#1Trying to subclass a sealed class outside its module or file.
Wrong approach:class ExternalSubclass : Result() // in a different file or module
Correct approach:class InternalSubclass : Result() // inside the same file or module
Root cause:Misunderstanding that sealed classes restrict subclassing location to ensure all subclasses are known.
#2Using sealed classes when you only need simple constants.
Wrong approach:sealed class Direction { object NORTH : Direction() object SOUTH : Direction() }
Correct approach:enum class Direction { NORTH, SOUTH }
Root cause:Not recognizing that enum classes are simpler and more efficient for fixed constant sets.
#3Ignoring compiler warnings about non-exhaustive when expressions with sealed classes.
Wrong approach:when(result) { is Success -> ... } // missing Failure case, no warning if used as statement
Correct approach:when(result) { is Success -> ... is Failure -> ... } // all cases handled
Root cause:Not understanding that exhaustive checks depend on how when is used (expression vs statement).
Key Takeaways
Sealed classes restrict subclassing to a known set, enabling safer and clearer code.
They allow the compiler to check that all cases are handled, reducing bugs in control flow.
Sealed classes differ from enums by supporting subclasses with different data and behavior.
Kotlin 1.5+ introduced sealed interfaces for more flexible restricted hierarchies.
Sealed classes provide compile-time safety without adding runtime overhead.