Exploring Sealed Classes vs. Sealed Interfaces in Kotlin

Jay Patel
3 min readMar 22, 2024

In Kotlin, a modern and versatile programming language, developers have access to a variety of powerful features that facilitate concise and expressive code. Among these features are sealed classes and sealed interfaces, which offer mechanisms for defining restricted hierarchies and controlling implementations within Kotlin codebases. In this blog post, we’ll delve into the distinctions between sealed classes and sealed interfaces in Kotlin, their respective use cases, and how they contribute to writing more maintainable and robust Kotlin applications.

Sealed Classes: Defining Closed Class Hierarchies

Sealed classes in Kotlin allow developers to define closed class hierarchies, wherein all subclasses must be defined within the same file as the sealed class itself. This restriction provides clarity and predictability, as it prevents the creation of subclasses outside of the defined hierarchy.

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

In the example above, the `Result` sealed class has two sealed subclasses: `Success` and `Error`. These subclasses are nested within the `Result` sealed class, ensuring that they are the only possible subclasses.

Sealed classes are particularly useful for modeling finite states or outcomes, such as the result of a computation or the different states of a state machine.

Sealed Interfaces: Controlling Implementations

Sealed interfaces, introduced in Kotlin 1.5, operate similarly to sealed classes but apply to interfaces instead. They allow developers to control which classes can implement the interface, thus ensuring that only a predefined set of classes adhere to its contract.

sealed interface Shape {
fun area(): Double
}

class Circle(val radius: Double) : Shape {
override fun area(): Double = Math.PI * radius * radius
}

class Square(val sideLength: Double) : Shape {
override fun area(): Double = sideLength * sideLength
}

In this example, the `Shape` interface is sealed, and only the `Circle` and `Square` classes are permitted to implement it. Any attempt to implement the `Shape` interface with a class not listed as a permitted implementation will result in a compilation error.

Sealed interfaces are particularly useful for designing APIs and frameworks where interface contracts need to be enforced with a finite set of implementations.

Key Differences and Use Cases

While sealed classes and sealed interfaces share similar functionality, they serve different purposes and are suited to different use cases:

1. Hierarchy vs. Interface Contracts: Sealed classes control class hierarchies, dictating which subclasses can be defined within the hierarchy, while sealed interfaces govern interface implementations, specifying which classes can adhere to the interface contract.

2. Class Structure vs. Interface Flexibility: Sealed classes define closed class hierarchies with predefined subclasses, promoting clarity and predictability in the codebase. Sealed interfaces allow for more flexibility in class structure while enforcing a limited set of interface implementations.

3. State Representation vs. API Design: Sealed classes are ideal for modeling states, outcomes, or hierarchical structures within an application. Sealed interfaces are well-suited for designing APIs and frameworks where interface contracts need to be enforced with a finite set of implementations.

Conclusion

Sealed classes and sealed interfaces are powerful features in Kotlin that enable developers to define restricted hierarchies and control implementations within their codebases. By leveraging these features, Kotlin developers can enhance code safety, improve maintainability, and design more robust and predictable software systems.

Whether you’re modeling states within your application or designing APIs with clear interface contracts, understanding the distinctions between sealed classes and sealed interfaces empowers you to make informed design decisions and write cleaner, more maintainable Kotlin code.

--

--