What is the difference between sealed class vs sealed interface in kotlin

20.2k views Asked by At

With Kotlin 1.5 was introduce the sealed interface. Even that I know the difference between classes and interfaces, I'm not clear what are the best practices and beneficies of using sealed interface over sealed class

Should I always use interface now even when is a simple case? Or will be a case by case?

Thanks

Obs: Didn't found similar questions, only about sealed classes

2

There are 2 answers

4
Tenfour04 On BEST ANSWER

A major reason to choose to use a sealed class instead of interface would be if there is common property/function that you don't want to be public. All members of an interface are always public.

The restriction that members must be public can be worked around on an interface using extension functions/properties, but only if it doesn't involve storing state non-publicly.

Otherwise, sealed interfaces are more flexible because they allow a subtype to be a subclass of something else, an enum class, or a subtype of multiple sealed interface/class hierarchies.

1
Sergio On

I would also add that sealed interface can be chosen instead of a class to mark an object with additional characteristics and use it in the when statement. For example let's say we have some number of classes that inherited from a sealed class Device:

sealed class DeviceItem(val name: String) {
    object Camera : DeviceItem("Camera")
    object Lamp : DeviceItem("Lamp")
    // ... etc, more devices
}

And we need to use an instance of DeviceItem in when statement, but we don't want to handle all the items, only specific items:

fun onDeviceItemClicked(item: DeviceItem) {
    when (item) {
        // ....
    }
}

In this case we should either add all device items to the when statement with an empty body for devices that we don't want to handle, and the code becomes cumbersome, or use else statement to handle those device items with the empty body. But if we use else we will not be notified of the error, when a new device item is added and requires some handling, which can lead to bugs. Starting from Kotlin 1.7 it will be a compilation error if when operator is not exhaustive. So basically to handle such cases we can provide a sealed interface and handle only items, which implement it:

sealed interface ClickableItem

sealed class DeviceItem(val name: String) {
    object Camera : DeviceItem("Camera"), ClickableItem
    object Lamp : DeviceItem("Lamp")
    // ... etc, more devices
}

fun onDeviceItemClicked(item: ClickableItem) {
    when (item) {
        Camera -> { /* do something */ }
    }
}

In this case when a new device item, which implements ClickableItem interface, is added there will be a compilation error, saying that when statement should be exhaustive and we must handle it.