Achtergrond:
Sealed interfaces zijn in Kotlin ontstaan als een uitbreiding van het concept van sealed classes. Tot Kotlin 1.5 konden alleen sealed classes het aantal mogelijke afgeleiden klassen beperken, wat bijzonder belangrijk is voor veilige werking met toestandsstructuren (state machines, DSL, etc.). Door sealed interfaces in te voeren, kregen ontwikkelaars de mogelijkheid om op vergelijkbare wijze implementaties van interfaces te beperken, zonder aan klassen gebonden te zijn.
Probleem:
Een gewone open interface kan overal in de applicatie worden geïmplementeerd, wat kan leiden tot een ongecontroleerde toename van implementaties en een complicatie van de codeondersteuning. Bij het verwerken met een when-expressie kan de compiler niet waarschuwen voor ongecontroleerde takken.
Oplossing:
Een sealed interface beperkt implementaties tot diegene die in hetzelfde module (of hetzelfde bestand, als de interface geen top-level is) zijn gedefinieerd. Dit type controle wordt toegepast voor veilige enum-achtige structuren, het ADT-patroon en statusbeheerders. De compiler kent alle implementaties en helpt bij het code-analyse.
Voorbeeldcode:
sealed interface NetworkResult class Success(val data: String): NetworkResult class Error(val cause: Throwable): NetworkResult object Loading: NetworkResult fun handleResult(result: NetworkResult): String = when (result) { is Success -> "Success with ${result.data}" is Error -> "Error: ${result.cause.message}" Loading -> "Loading..." }
Belangrijke kenmerken:
when-expressies: de compiler controleert de exhaustiveness.Kan een sealed interface buiten het huidige bestand worden geïmplementeerd?
Antwoord: In tegenstelling tot sealed classes kunnen sealed interfaces in andere bestanden worden geïmplementeerd, maar alleen binnen hetzelfde module (of compilatie-eenheid, als de interface geen top-level is).
Kunnen sealed interfaces open methoden met standaardimplementaties hebben?
Ja, net als gewone interfaces kan een sealed interface default-implementaties van functies bevatten.
sealed interface Mode { fun description(): String = "Unknown mode" }
Is het mogelijk om een sealed interface te serialiseren met behulp van standaard serialisators (bijvoorbeeld kotlinx.serialization)?
Ja, maar het is nodig om expliciet alle implementaties op te geven. In Kotlinx.serialization kwam de ondersteuning voor sealed interfaces niet onmiddellijk, het is belangrijk om de te serialiseren types expliciet op te geven.
In een project werd een sealed interface beschreven voor alle typen UI-toestanden, maar de implementaties begonnen op verschillende plaatsen in de applicatie te verschijnen. Toen werd er een nieuw type toestand toegevoegd en vergeten om het verwerkingsblok bij te werken, wat leidde tot het negeren van de nieuwe toestand in de logs.
Voordelen:
Nadelen:
Een sealed interface werd gebruikt voor alle netwerkomzetten. Hierdoor gaf de IDE direct aan alle plaatsen aan waar de verwerking via when gebeurde bij het toevoegen van een nieuw type antwoord. Fout wordt direct hersteld, geen onverwachte gaten in de logica.
Voordelen:
Nadelen: