Donnerstag, 24. Mai 2012
Jetzt neu: Onlinezugriff auf das digitalisierte Archiv des Entwickler Magazins

Artikel

April 2010 | Artikel

Scala, oder: Was hat es mit dem Hype auf sich? Ein kurzer Überblick Fortsetzung, Teil 2

Teil 1   Teil 2   

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.

  1. val persons = List(Person("Axel", "Adams"),
  2. Person("Armin", "Apfel"),
  3. Person("Guido", "Gelb"),
  4. 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.

Teil 1   Teil 2   

Kommentare

Gravatar raksch 30.04.2010
um 12:33 Uhr
sorry, aber das Beispiel mit der Person-Bean ist seltendämlich. In Java kann ich auch auf getter und setter verzichten und mache alle Variablen public, aber das tue ich nicht, aus gutem Grund.
Der Artikel ist einfach unseriös, deswegen werde ich ihn auchl nicht weiterlesen.
#zitieren
Gravatar Stefan 10.05.2010
um 15:54 Uhr
Und wenn sie nicht an der funktionale Programmierung gestorben sind dann freuen sie sich heute noch...Tut mir leid aber der Stil des Beitrages ist vorsichtig genannt einfach nur peinlich! #zitieren
Gravatar Peter Liersch 21.05.2010
um 08:57 Uhr
Die Lernkurve für Java-Programmierer ist steil - es ist falsch zu glauben man könne "mal eben" auf Scala umsteigen. Die Unterschiede sind immens.

Scala ist keine leichte Programmiersprache.
Scala ist vor allem nicht leichter als Java. Im Gegenteil hat es viele Elemente und Konzepte, die gerade von "klassischen Java-Entwicklern" unnötig viel abverlangen. Der Code mag kürzer sein, in großen Projekten ist er aber sogar schwerer zu erfassen als Java.

Ein Wechsel von der OOP zur oder auch ein echter Einstieg in funktionale Programmierung ist mit einem grossen Umdenken verbunden.

Scala ist für den universitären Bereich hervorragend, im produktiven Einsatz bietet es kaum echte Vorteile gegenüber dem klassischen Java.

Scala ist sehr gut, aber weder für alle noch für alle Einsatzgebiete. Und es ist definitiv kein Ersatz für Java.
#zitieren
Gravatar Michael 08.06.2010
um 19:30 Uhr
Schön leicht und kurz der Quellcode nur muss man für jede Zeile die man in Scala schreibt anscheinend fünf weitere Zeilen kommentieren. Und vorher muss man natürlich immer schön nachgooglen wie man was macht. Viel Spass damit in einem grossen Projekt. Die Performance ist bei Interpretersprachen auch immer super deshalb finde ich die Idee von virtuellen Maschinen auch absolut super genauso wie Hans oder hieß der jetzt Lars??? #zitieren
Gravatar Dominik 01.07.2010
um 19:41 Uhr
"Und vorher muss man natürlich immer schön nachgooglen wie man was macht" #zitieren
Gravatar Richard 16.07.2010
um 12:27 Uhr
@raksch In diesem Beispiel sind die Variablen keinesfalls public es sind weiterhin (in diesem Trivialfall implizite) getter vorhanden. (val statt var bedeutet in etwa "final")@ Peter Scala verbindet sehr elegant OOP und funktionale Programmierung ein "Umstieg" ist hier nicht erforderlich@Michael Scala wird in JVM Bytecode übersetzt und ist idr. gleich schnell wie JavaWas der Bauer nicht kennt frisst er nicht (und lässt dadurch so manchen Leckerbissen entgehen) #zitieren
Gravatar René 17.03.2011
um 23:48 Uhr
Ich sehe das erste Beispiel nicht so kritisch wir raksch. Man mag natürlich zunächst denken das hier das Prinzip des Information Hidings verletzt wird weil eigentlich zu kapselnde interne Member von außen zugreifbar sind. Tatsächlich ist die Implementierung des Zugriffs nachträglich ohne Schnittstellenänderung möglich // 1. alte Implementierung mit impliziten trivialen Gettern und Setternclass Person(var firstName: String var lastName: String)// 2. neue Implementierung mit nicht-trivialen expliziten Getter und Setter für firstNameclass Person(private val initialFirstName:String lastName:String) { /* private member 'privateFirstName' wird mit dem Konstruktor-parameter 'initialFirstName' initialisiert */ private var privateFirstName: String = initialFirstName // getter def firstName = { // simples Logging println("Der firstName '" + value + "' wird zurückgegeben") privateFirstName } // setter def firstName_=(value: String) = { // simples Logging println("Der firstName wird zu '" + value + "' geändert"); privateFirstName = value }}...// Zugriff für beide Implementierungvariantenvar myPerson = new Person("Hans" "Wurst");println(myPerson.firstName)myPerson.firstName = "Heinz" println(myPerson.firstName)Vorteile:1. Übersichtliche Property-Syntax wie in C# mit einem Zuweisungsoperator = in der Mitte also statt getX().getY().setZ(getA().getB()) dann x.y.z = a.b2. Man spart sich gegenüber Java die Implementierung der trivialen Getter und Setter die ja wohl eher Regel als Ausnahme sind. Wie beschrieben können die impliziten trivialen Getter/Setter in Scala zu expliziten nichtrivialen erweitert werden ohne die Schnittstelle der betreffenden Klasse zu ändern. Etwas Vergleichbares kennt Java nicht. #zitieren
Gravatar René 17.03.2011
um 23:51 Uhr
Arrgh... wenigstens die Umbrüche hätte er mir lassen können... #zitieren
Gravatar Trepper 18.03.2011
um 09:04 Uhr
Scala bietet viel, was ich in Java vermisse, aber Scala Code scheint mir in der Praxis eher weniger verständlich als Java-Code zu sein. Dass man beliebige Operatoren definieren kann, fördert nicht gerade die Lesbarkeit; Funktionen die ohne "." und "()" aufgerufen werden auch nicht. Implizite Konvertierungen tun ihr übriges.

Obwohl ich Scala mag, habe ich Zweifel, ob das die Sprache sein wird, die zu dauerhaft wartbaren und wirtschaftlichen Projekten führen wird. Ehrlich gesagt finde ich in diesem Punkt C# viel besser, dann das ist deutlich moderner als Java zieht aber im Gegensatz zu Scala ein paar sinnvolle Grenzen.

Bemerkenswert finde ich auch wie viel lesbarer Python-Code gegenüber Scala ist.
#zitieren