Die Programmiersprache Scala setzt die Kunst des funktionalen Programmierens pragmatisch um. Mit wenig Schreibarbeit, Funktionen höherer Ordnung und Comprehensions erfreut sie den Entwickler, im Orchester mit Java zelebriert sie bei Twitter & Co. spektakuläre Auftritte.
Funktionale Programmiersprachen wie Lisp oder Haskell verlassen nur höchst selten ihr eigenes Ökosystem. Wer nicht gerade Emacs-Erweiterungen schreibt oder den Fenstermanager Xmonad verwendet, kommt mit ihnen kaum in Berührung. Die Programmiersprache Scala [1] dagegen ist weitgehend mit Java interoperabel und kompiliert zu Bytecode für die JVM.
Damit wird sie für den IT-Mainstream tauglich. Das zeigt auch ihr Einsatz bei Internetunternehmen wie Twitter, Linked In oder Foursquare, die Teile ihrer Produktivsysteme in Scala umgesetzt haben. Am Abend des 7. November 2012 bescherten die US-Wahlen Twitter einen neuen Rekord mit rund 10000 Tweets pro Sekunde. Die in einer Mischung aus Scala und Java umgesetzte Serversoftware bewältigte die Spitzenlast ohne Ausfälle [2].
Javas Großnichte
Die Verwandtschaft mit Java war Scala bereits in die Wiege gelegt. Ihr Erfinder, der deutsche Informatiker Martin Odersky, arbeitete ab 1995 zusammen mit Philip Wadler an einer funktionalen Sprache für die Java-VM. Die Resultate finden sich in Java Generics und dem Java-Compiler »javac« . Daneben entwickelte er nach ein paar Umwegen ab 2001 Scala, die 2003 die offizielle Veröffentlichung erfuhr. Sie fand am Programming Methods Laboratory der École Polytechnique Fédérale De Lausanne (EPFL) statt, wo Professor Odersky bis heute die Sprache weiterentwickelt und pflegt [3]. Scala steht unter einer BSD-artigen Open-Source-Lizenz und lässt sich auf Linux-Distributionen wie Debian, Ubuntu oder Open Suse aus dem Paketarchiv installieren.
Ein minimales Scala-Programm sieht aus wie Listing 1. Es besteht aus einem Objekt mit einer »main()« -Methode. Quelltextdateien in Scala übersetzt der Scala-Compiler zu Java-Klassen:
Listing 1
HelloWorld.scala
01 object HelloWorld {
02 def main(args: Array[String]) {
03 println("Hello, world!")
04 }
05 }
scalac HelloWorld.scala
Das Ergebnis lässt sich mit der JVM ausführen:
scala -classpath . HelloWorld
Daneben gibt es wie bei traditionellen funktionellen Sprachen eine interaktive Kommandozeile mit der Read Eval Print Loop (REPL). Das Kommando »scala« eröffnet die Sitzung (Abbildung 1). Eine weitere Variante besteht darin, Scala-Code in ein Shellskript zu verpacken, das ihn an das Scala-Utility weiterreicht. Im Hintergrund kompiliert dieses den Quelltext und führt ihn mit dem installierten JDK aus. Listing 2 schreibt “Hallo” zusammen mit dem ersten Kommandozeilen-Argument auf das Terminal.
Listing 2
Scala als Skript
01 #!/bin/sh
02 exec scala "$0" "$@"
03 !#
04
05 println("Hallo " + args(0))
Auf der Basis von Eclipse gibt es eine integrierte Scala-Entwicklungsumgebung [4]. Sie stammt von der Firma Typesafe, deren Chefarchitekt Martin Odersky ist und die zahlreiche Produkte und Dienstleistungen rund um die Programmiersprache anbietet. Die Open-Source-IDE validiert den Code während der Eingabe, hilft beim Formatieren und Überarbeiten und stößt den Übersetzungsvorgang an. Daneben integriert sie Unit-Tests (Abbildung 2). Für die Umgebungen Netbeans, Intelli-J sowie Emacs und Vim existieren ebenfalls Scala-Erweiterungen.

Abbildung 2: Auf der Basis von Eclipse gibt es eine Scala-IDE, die das Kompilieren und Testen vereinfacht.
Scala ist eine funktionale Programmiersprache. Das heißt, sie konzentriert sich auf Funktionen und ihre Rückgabewerte. Diese Funktionen geben bei gleicher Eingabe stets das gleiche Ergebnis aus. Ihr Verhalten lässt sich daher mit Unit-Tests auf Korrektheit prüfen, bevor der Entwickler sie zu einer größeren Anwendung zusammensetzt.
Zudem vermeidet es die funktionale Programmierung, den Wert bestehender Variablen zu ändern. Der Scala-Compiler setzt dieses Prinzip praktisch um. Die Zeilenfolge
val x = 3 x = 4
quittiert er mit einer Fehlermeldung. Das Vermeiden eines solchen Mutable State macht funktionale Sprachen für die parallele und nebenläufige Programmierung interessant: Wenn kein Thread den Zustand eigenmächtig ändert, passt am Ende alles wieder zusammen. Diese Eigenschaft macht Scala laut Odersky zu einer hervorragenden Sprache für die Multicore-Ära: Im Idealfall reiche es, ».par« an ein Array anzuhängen [5].
Scala erlaubt als pragmatische Sprache jedoch Ausnahmen: Ausschließlich die mit »val« zugewiesenen Werte sind unveränderlich, stellt der Programmierer stattdessen »var« voran, darf er den Wert ändern. Die Programmiersprache erlaubt auch gelegentlich den imperativen Programmierstil – schließlich gibt es Aufgaben, die dieser am besten löst.
Lisp-Erbe
Ansonsten atmet alles an Scala den funktionalen Geist von Lisp, Scheme und Haskell: Funktionen behandelt die Sprache als Bürger erster Klasse. Sie dürfen allerorten definiert sein, auch als innere Funktionen innerhalb anderer. Daneben kann der Programmierer sie wie jeden anderen Wert behandeln und auch als Eingabe oder Rückgabe für andere Funktionen verwenden [6].
Die kurze Interaktion in Abbildung 3 zeigt mehrere funktionale Charakteristika: Funktionen höherer Ordnung wie Map nehmen andere Funktionen als Argumente entgegen. In diesem Fall ist das die anonyme Funktion »x => x * 2« , die einen Wert auf sein Doppeltes abbildet. Map wendet sie auf jedes Element der Liste an. Statt der Multiplikation könnte der Programmierer auch eine Funktion übergeben, die jedes Element potenziert, seine Quadratwurzel zieht oder eine andere Operation vornimmt.

Abbildung 3: Funktionen lassen sich in Scala wie gewöhnliche Objekte behandeln und auch an andere Funktionen übergeben.
Im Unterschied zu Java erlaubt Scala auch die Infix-Notation »li map f« , die sich in machen Fällen leichter liest als »li.map(f)« . Ebenfalls bemerkenswert: Scala ist statisch typisiert, und dennoch braucht der Anwender den Datentyp nicht immer anzugeben. Der Compiler beherrscht Typeninferenz und bemerkt im Beispiel automatisch, dass die Elemente der Liste vom Typ Integer sind.
Rekursion
Wo imperative Sprachen For- und While-Schleifen verwenden, um mehrere Elemente zu verarbeiten, benutzt Scala Rekursion. Dies demonstriert die Funktion »myReverse()« in Listing 3, die die Reihenfolge der Element einer Liste umkehrt. Zu diesem Zweck nimmt sie das erste Element (»l.head« ) und hängt es an den verbleibenden Teil (»l.tail« ) der Liste an. Anschließend ruft sich die Funktion in Zeile 3 selbst auf, mit dem Listenrest als Parameter, um auch diesen umzukehren. Mit jedem Durchgang der Rekursion kürzt die Funktion »head()« die verbleibende Liste um ein Element, bis sie schließlich leer ist. Damit wird die Bedingung »l.isEmpty« wahr und die Rekursion endet.
Listing 3
Rekursion
01 def myReverse[T](l: List[T] ): List[T] = {
02 if (l.isEmpty) l
03 else myReverse(l.tail) :+ l.head
04 }
05
06 val l = List(1,2,3,4)
07 myReverse(l)
Beim Einsatz von Rekursion muss der Programmierer diese so genannte Abbruchbedingung richtig definieren, wenn er nicht durch Endlosschleifen den Speicher zum Überlauf bringen will. Die Funktion in Listing 3 funktioniert im Übrigen für Listen, die einen beliebigen Elementtyp enthalten, sei es eine Ganzzahl, ein Buchstabe, wiederum eine Liste oder ein selbst gemachter Datentyp. Der Platzhalter »T« fungiert als Typenparameter. Er stellt auch sicher, dass die umgedrehte Liste den Elementtyp beibehält.
Objektorientiert
Um Ordnung in Datentypen und Funktionen zu bringen, verwendet Scala wie Java Objektorientierung. Die Standardbibliothek genauso wie maßgeschneiderter Code definieren Klassen wie etwa »List« , aus denen man durch Instanzierung konkrete Objekte wie etwa die Liste »l« in Listing 2 erzeugt. Klassen bündeln die Eigenschaften der Objekte und enthalten zudem Methoden, also jene Funktionen, die angeben, was der Programmierer mit einem Objekt anstellen darf.
Ein hierarchisches System von über- und untergeordneten Klassen regelt die Vererbung: Subklassen erben Eigenschaften und Methoden von den übergeordneten. Scala kennt auch abstrakte Klassen, die sich nicht selbst instanzieren lassen. Sie dienen lediglich dazu, gemeinsame Eigenschaften und Methoden auf ihre Unterklassen zu vererben.
In Listing 4 ist eine abstrakte Klasse »GeoObject« für geometrische Objekte definiert. Sie schreibt ihren Unterklassen vor, die Methode »symbolize()« umzusetzen. Das tun »Point« und »Circle« , indem sie jeweils einen Punkt oder den Buchstaben O ausgeben. Zudem besitzt »Circle« noch eine weitere Methode zur Berechnung der Kreisfläche.
Listing 4
Abstrakte Klasse
01 abstract class GeoObject {
02 def symbolize: String
03 }
04
05 class Point extends GeoObject {
06 def symbolize: String = "."
07 }
08
09 class Circle(r: Double) extends GeoObject {
10 def symbolize: String = "O"
11 def area: Double = r * r * 3.14
12 }
13
14 val p = new Point
15 val c = new Circle(2.0)
16
17 p.symbolize
18 c.symbolize
19 c.area
Scala benutzt Mehrfachvererbung mittels so genannter Traits, die fast genauso wie abstrakte Klassen notiert werden. Sie entsprechen in etwa den Interfaces in Java. Eine Scala-Klasse kann zwar nur eine einzige übergeordnete Klasse beerben, aber mehrere Traits.
Collections
Die gebräuchlichsten Datentypen fasst Scala unter dem Begriff Collections zusammen. Sie lassen sich mit dem Vokabular von ein paar Dutzend Methoden bearbeiten [7]. Dazu gehört die Liste als klassisches Arbeitspferd der funktionalen Programmierung (Abbildung 4). Aufgrund ihres Aufbaus aus Zellen macht sie den Zugriff auf das erste Element schnell, am Ende oder in der Mitte aber langsam. Scala stellt der Liste daher den »Vector« zur Seite, der ebenso wie sie selbst eine Unterklasse der »Sequence« darstellt. Der Vektor besitzt ein ausgeglicheneres Zugriffsmuster, da er eine Baumstruktur verwendet, die sich für Random Access besser eignet.

Abbildung 4: Scala-Standardbibliothek: Die Liste nimmt einen wichtigen Platz unter den Datentypen ein.
Daneben gibt es in Scala »Range« , eine Sequenz von Ganzzahlen in festem Abstand. Die Notation ist denkbar prägnant: Mit »2 until 50 by 2« kann der Programmierer etwa alle geraden Zahlen bis ausschließlich 50 beschreiben. Die Typen String und Array leiht sich Scala von Java, weshalb sie nicht fest in der Scala-Hierarchie verankert sind.
Die Geschwister der Sequences sind »Set« und »Map« , die ebenfalls zu den Collections gehören. Ein Set enthält im Unterschied zur Liste keine doppelten Elemente und lässt sich mit Operationen der Mengenlehre abfragen und bearbeiten. Die »Map« besteht aus Schlüssel-Wert-Paaren. Sie stellt nicht nur eine Collection dar, sondern auch eine Funktion. Eine Map mit der Definition
val descriptor = Map (0 -> "Stdin", 1 ->"Stdout", 2 -> "Stderr" )
lässt sich daher wie eine Funktion auf einen Schlüssel anwenden. Der Aufruf »descriptor(2)« ergibt die Standardfehlerausgabe.
Eine besondere Scala-Sequenz ist der »Stream« . Er ähnelt der Liste, doch der zweite Teil seiner Zellen wird nur bei Bedarf ausgewertet. Solange keine andere Funktion sie als Argumente benötigt, berechnet Scala diesen Teil auch nicht. Die Strategie der Lazy Evaluation, in der Sprache Haskell standardmäßig eingesetzt, kann der Scala-Programmierer auch für andere Typen wählen, indem er schreibt:
lazy val x = Ausdruck
Lazy Streams ermöglichen es dem Programmierer, mit unendlichen Sequenzen zu arbeiten, ohne dass der Rechner heiß läuft. Solange er lediglich einen Teil der Sequenz weiterverarbeitet, evaluiert Scala auch nur diesen. Abbildung 5 zeigt zusammenfassend den Aufbau der Typen »Stream« , »List« und »Vector« .

Abbildung 5: Der Aufbau wichtiger Scala-Datentypen: Die Liste erlaubt raschen Zugriff auf das erste Element, der Vektor nimmt auch große Sequenzen auf und schafft ein ausgeglichenes Zugriffsmuster. Der Stream verwendet Bedarfsauswertung und verrät seine Elemente erst, wenn sie angefordert werden.
Gib Zucker
Eine effiziente Möglichkeit, in Scala Collections zu definieren, bieten die so genannten For-Comprehensions. Nach dem Schlüsselwort »for« folgen in geschweiften Klammern ein oder mehrere Generatoren, die Sequenzen erzeugen. Nach der Klammer kommen »yield« und der Ausdruck für das gewünschte Ergebnis.
Was sich in der Theorie wenig greifbar anhört, ist in der Praxis verständlich und praktisch: Listing 5 formuliert mit einer For-Comprehension das gute alte Einmaleins. Die Generatoren »i« und »j« erzeugen je eine Sequenz der Zahlen 1 bis 9, der Yield-Ausdruck kombiniert alle zu dem bekannten Grundschul-Sprüchlein.
Listing 5
For-Comprehension
01 for {
02 i <- 1 to 9
03 j <- 1 to 9
04 } yield j + " mal " + i + " ist " + (i * j)
Die als zweite genannte Range »j« wird schneller durchlaufen als »i« , darum steht sie in dem traditionellen Einmaleins-Sprüchlein auch am Anfang (siehe Abbildung 6). Innerhalb der geschweiften Klammern im Listing dürfte außerdem noch ein Filter stehen.
Mit solchen Comprehensions kann der Scala-Programmierer seine Daten, die er typischerweise in Collections speichert, wirkungsvoll kombinieren, umformen und filtern. Sie sind eigentlich nur Syntactic Sugar, eine anwenderfreundliche Notation für eine Kombination aus den Funktionen »map()« , »flatMap()« und »filter()« , in die sie der Compiler übersetzt. Daher eignen sich alle Collections, die diese Methoden umsetzen, zur Verarbeitung mit Comprehensions.
Frameworks
Hiermit sind einige Features und Konstrukte von Scala beschrieben, aber längst nicht alle. Eine Tour auf der Scala-Homepage [8] stellt weitere vor, beispielsweise Mixins, Closures und Pattern Matching. Aus kleinen Bausteinen sind zudem leistungsfähige Bibliotheken und Frameworks entstanden. Dazu gehört Akka [9], ein Concurrency-Framework, das ähnlich wie die Programmiersprache Erlang das Actor-Konzept umsetzt. Für Webanwendungen stehen Play [10] und Lift zur Verfügung.
Ein eigenes Buildtool existiert auch, es heißt SBT (Simple Build Tool, [11]) und ist selbstverständlich in Scala implementiert. Zum Einstieg in die Programmiersprache eignet sich beispielsweise das Tutorial beim Scala-Anwender Twitter [12]. Das Standardwerk zur Sprache hat deren Erfinder Martin Odersky zusammen mit zwei Kollegen veröffentlicht [13]. Daneben gibt es von ihm ein unvollendetes Werk namens “Scala By Example” [14], das auf der Homepage der Programmiersprache als PDF herunterzuladen ist.
Infos
- Scala: http://www.scala-lang.org
- Twitters Engineering Blog, “Bolstering our infrastructure”: http://engineering.twitter.com/2012/11/bolstering-our-infrastructure.html
- Programming Methods Laboratory der EPFL: http://lamp.epfl.ch
- Scala-IDE: http://scala-ide.org
- Martin Odersky, “Working Hard to Keep It Simple”: http://www.youtube.com/watch?v=3jg1AheF4n0
- Rainer Grimm, “Raus aus der akademischen Nische: Funktionale Programmierung”: https://www.linux-magazin.de/Online-Artikel/Funktionale-Programmierung-1-Grundzuege
- Scala-Collections: http://docs.scala-lang.org/overviews/collections/introduction.html
- “A Tour of Scala”: http://www.scala-lang.org/node/104
- Akka: http://akka.io
- Play: http://www.playframework.org
- SBT: http://www.scala-sbt.org
- Twitters Scala School: http://twitter.github.com/scala_school/
- Martin Odersky, Lex Spoon, Bill Venners, “Programming in Scala, Second Edition”: Artima, 2010
- Martin Odersky, “Scala By Example”: http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaByExample.pdf








