Kotlin macht Spaß: Sealed Interfaces + when

Kotlin hat sich aus verschiedenen Programmiersprachen das Beste zusammengeklaut.
So erlaubt die Kombination von Sealed Interfaces und when sehr schönen und klaren Code. Der gleichzeitig auch noch sehr gut vom Compiler auf Korrektheit überprüft wird!

// Stub function to simulate fetching a response
private fun getResponse(): Response = TODO()

fun main() {
  // Call a method with a relaxed return type. 
  // This ensures the compiler treats 'response' as 'Response' rather than a specific subtype, avoiding compile-time warnings.
  val response: Response = getResponse()

  // Using 'when' with all concrete types. Skipping one type results in a compile error due to exhaustiveness checking.
  when (response) {
    is Response.Success.Success1 -> println("S1")
    is Response.Success.Success2 -> println("S2")
    is Response.Failure.Failure1 -> println("F1")
    is Response.Failure.Failure2 -> println("F2")
  }

  // Handling multiple types in one code block using commas.
  when (response) {
    is Response.Success.Success1,
    is Response.Success.Success2,
    is Response.Failure.Failure1,
    -> println("combined S1, S2, F1")  // Note the trailing comma for readability

    is Response.Failure.Failure2 -> println("F2")
  }

  // Handling all failure cases in one block by using the common interface 'Failure'
  when (response) {
    is Response.Success.Success1 -> println("S1")
    is Response.Success.Success2 -> println("S2")
    is Response.Failure -> println("Failure case") // This will match Failure1 and Failure2 both
  }

  // Handling Success and Failure cases together by their common interfaces
  when (response) {
    is Response.Success -> println("Success case")  // This will match Success1 and Success2
    is Response.Failure -> println("Failure case")  // This will match Failure1 and Failure2
  }
}

// Define a sealed interface 'Response' which can be either a Success or a Failure
sealed interface Response {
  
  // Define a nested sealed interface 'Success' under 'Response'
  sealed interface Success : Response {
    // Define concrete data classes for Success1 and Success2 which implement the Success interface
    data class Success1(val foo: String) : Success
    data class Success2(val bar: String) : Success
  }

  // Define a nested sealed interface 'Failure' under 'Response'
  sealed interface Failure : Response {
    // Define concrete data classes for Failure1 and Failure2 which implement the Failure interface
    data class Failure1(val foo: String) : Failure
    data class Failure2(val foo: String) : Failure
  }
}

Code-Sprache: Kotlin (kotlin)

Vorteile / Features

Sealed Interface-Hierarchie

Das Response-Interface ist sealed, was bedeutet, dass alle möglichen Unterklassen zur Compile-Time bekannt sind. Dadurch ist der when-Ausdruck exhaustiv – wir können nichts vergessen!

Unterschiedliche „Genaugigkeiten“ beim Machting

Durch die Typ-Hierarchie innerhalb der Sealed Interface können wir jetzt unterschiedliche Genauigkeiten matchen. Wir können z.B. alles Failure oder Success-Cases gemeinsam abhandeln.
Der Compiler übernimmt die Checks und fügt „Smart Casts“ hinzu.

Diese Beispiele zeigen, wie mächtig und flexibel sealed Interfaces und der when-Ausdruck in Kotlin sind, um komplexe Typ-Hierarchien zu handhaben und die Kompilierzeit-Sicherheit zu gewährleisten.