Scala ist (auch) funktional
Dieser Argumentation kann sich nicht einmal Guido entziehen, doch so schnell gibt er nicht auf: „Das war jetzt ein geschickt gewähltes Beispiel, aber wenn es um komplexe Programmlogik anstelle von einfachen JavaBeans geht, dann ist Java mit seinen modernen OO-Features unschlagbar.“
So so“ antwortet Martin, „lass uns doch einmal komplexe Programmlogik betrachten. Wie wäre es damit, ein Abfrageergebnis für die GUI zu filtern und zu sortieren? Nehmen wir doch unsere Person und filtern alle heraus, deren Nachname nicht mit A beginnt und sortieren dann nach dem Nachnamen. Das machen wir in Scala so, wobei wir den Code jetzt gleich in die Scala REPL eingeben, eine interaktive Console, die den Code sofort interpretiert“: case class Person(firstName: String, lastName: String).
„Zunächst seht ihr, dass ich Person zur Case Class gemacht habe. Dadurch können wir uns beim Erzeugen von neuen Instanzen das new sparen, wie ihr in der darauf folgenden Erzeugung einer Liste seht. Außerdem bekommen wir vernünftige Implementierungen von toString, equals und hashCode geschenkt.
val persons = List(Person("Axel", "Adams"),Person("Armin", "Apfel"),Person("Guido", "Gelb"),Person("Helmut", "Lauch"))
„Hier seht ihr, dass wir darauf verzichten können, Typen anzugeben. Aber keine Angst, Scala ist statisch typisiert. Der Compiler ist einfach schlau genug, zu erkennen, worum es sich handelt, in unserem Fall eben um eine List vom Typ Person. Das nennt man Type Inference. Ebenso dürftet ihr inzwischen gemerkt haben, dass wir keine Strichpunkte benötigen. Dadurch wird der Code wiederum leichtgewichtiger und knapper. Kommen wir zur eigentlichen Aufgabe, zunächst zum Filtern“: persons filter { p => p.lastName startsWith "A" }.
„Wir rufen einfach auf der persons-Liste die Methode filter auf, wobei wir den Punkt weglassen und das Argument in geschweifte Klammern schreiben. Das Argument ist ein Funktionsliteral, so etwas Ähnliches wie eine Closure, die möglicherweise in Java 7 kommt oder auch nicht. Links vom Pfeil stehen die Parameter, rechts vom Pfeil der „Body“, hier nur ein Einzeiler. Wegen der Type Inference weiß der Compiler, dass p eine Person ist, sodass wir lastName aufrufen dürfen. Die filter-Methode erwartet eine Funktion, die true oder false zurückgibt, und genau das macht unser Aufruf von startsWith, auch wenn wir das return weglassen. Das Ergebnis ist eine gefilterte Liste, auf der wir gleich mit der Sortierung weitermachen können. Die Methode sortWith erwartet wiederum ein Funktionsliteral, diesmal mit zwei Parametern. Der Rest ist analog zur filter-Methode“: persons filter { ... } sortWith { (p1, p2) => p1.lastName < p2.lastName }.
„So einfach geht das? Das kann ja sogar ich einigermaßen verstehen!“ wirft Helmut ein, der schon lange nicht mehr programmiert.
„Ja, Scala ist eben sehr ausdrucksstark und leichtgewichtig, genauso wie eine dynamisch typisierte Sprache, z. B. Ruby. Aber Scala ist eben statisch typisiert und das ist für unsere Software ein klarer Vorteil. Ein weiterer Grund, warum wir hier so schnell zum Ziel kommen ist, dass Scala eine objektfunktionale Sprache ist, die das Beste aus OO-Welt und funktionaler Programmierung zusammenbringt. Funktionale Programmierung ermöglicht uns zu sagen, was wir tun wollen. In Java hingegen müssen wir meist imperativ programmieren und sagen, wie wir es tun wollen. Das „Was“ ist abstrakter und daher knapper und einfacher hinzuschreiben.“
Guido pflichtet ihm bei: „In Java hätte ich jetzt mit irgendwelchen Objekten hantieren und verhältnismäßig viel Code schreiben müssen. Dabei geht es doch darum, eine „Handlung“ zu definieren, und da erscheint mir eine Funktion die natürliche Entsprechung zu sein.“
Sanfter Umstieg möglich
Mit dieser kleinen Geschichte haben wir zwei Highlights von Scala beleuchtet. Es gäbe so viele mehr, die den Rahmen dieses Artikels sprengen würden, z. B. Traits zur „Mehrfachvererbung richtig gemacht“, Pattern Matching als das „bessere Switch“ oder das mächtige Typsystem.
Einen Sachverhalt müssen wir jedoch noch erwähnen, denn dieser ist vermutlich der entscheidende für den Erfolg von Scala: Scala ist 100 % interoperabel mit Java. Das bedeutet, dass wir all unsere lieb gewonnenen Java Libraries wie Log4j, Hibernate, Spring etc. mit Scala verwenden können. Und natürlich auch unseren eigenen Java-Code. Dadurch müssen wir Scala nicht mit einem Big Bang einführen, sondern können langsam und iterativ, unter Berücksichtigung der Risiken, die jeder technologische Wandel bringt, umsteigen.
Ein typisches Szenario könnte so aussehen: Zunächst werden in einem ausgewählten Projekt alle neuen Test Cases in Scala geschrieben. Das erscheint recht unkritisch, bringt jedoch den Vorteil, mit einem Framework wie ScalaTest viel ausdrucksstärkere Testfälle schreiben und erste Scala-Erfahrung sammeln zu können. Im nächsten Schritt werden dann Teilprojekte, auf die keine Java-Projekte Abhängigkeiten haben (Zwiebelschalenprinzip), auf Scala umgestellt. Erst wenn nach ausreichender Zeit genügend Expertise und Vertauen aufgebaut wurde, erfolgt der komplette Umstieg.
Heiko Seeberger ist geschäftsfü̈hrender Gesellschafter der Weigle Wilczek GmbH und verantwortlich für die technologische Strategie des Unternehmens mit den Schwerpunkten Java, Scala, OSGi, Eclipse RCP und Lift. Zudem ist er aktiver Open Source Committer, Autor zahlreicher Fachartikel und Redner auf einschlägigen Konferenzen.



