Ich habe einen kleine Bibliothek zum Pattern-Matching in Kotlin geschrieben: https://github.com/DanielGronau/kopama
Die Idee ist, Pattern Matching in when-Ausdrücken zu ermöglichen. Die Syntax dazu ist ein wenig an Hamcrest Matcher angelehnt. Dazu kommen verschiedene Möglichkeiten, Objekte – insbesondere Collections und Data-Klassen – in ihre Bestandteile zu zerlegen. Hier ein einfaches Beispiel:
val p = Person("John", "Doe", 34)
when(match(p)) {
Person::class(any, any, le(18)) -> println("Eine minderjährige Person")
Person::class("John", "Doe", any) -> println("Es ist John Doe")
(eq("Alice") or eq("Bob"))[Person::firstName] -> println("Es ist Alice oder Bob")
else -> println("unbekannte Person")
}
Es gibt natürlich noch viele andere Patterns, von Null-Tests über Vergleiche bis zu Tests für Collections. Für komplizierte Zugriffspfade zu etwas versteckten Informationen kann man auch Lambdas verwenden. Es ist ebenfalls möglich, Werte zu zwischenzuspeichern und dann auf der rechten Seite wieder auszulesen – auch wenn die Syntax etwas umständlich ist. Pattern selbst sind nicht viel mehr als einfache Prädikate, es ist also auch nicht schwierig, seine eigenen zu schreiben.
Ein Problem der Bibliothek, das nicht wirklich zu vermeiden ist, ist die mangelnde Typsicherheit. Da das Zerlegen in einzelne Bestandteile über Reflection erfolgt, kann der zu erwartende Typ nicht korrekt vorherbestimmt werden. Deshalb kann man auch Pattern schreiben, die nicht sehr sinnvoll sind, etwa einen Vergleich von einem String mit einer Zahl. In solchen Fällen schlägt der Test fehl, wirft aber keinen Fehler. Im Endeffekt hilft hier nur Disziplin, Tests und etwas Augenmaß dafür, was eventuell schiefgehen kann.
Ich habe sehr viel bei der Arbeit an der Bibliothek gelernt, und es hat viel Spaß gemacht, das DSL zu designen. Für Vorschläge und Kritik bin ich immer dankbar.