Ich lerne Scala – Tag 3
Ich lerne im Moment die Programmiersprache Scala. Aktuell arbeite ich mich jeden Tag wenn ich die Zeit dazu finde durch ein Kapitel des Buches „Programming in Scala“. Das Buch ist von den Machern der Sprache, als Tutorial aufgebaut, und richtet sich an Leute mit Programmiererfahrung, wenn auch keine Kenntnisse in irgendeiner Sprache verlangt werden.
Wie im gestern besprochenen Kapitel 2 gibt das Buch in Kapitel 3 einen Überblick über die wichtigsten Sprachelemente, dabei wird auch oft der Vergleich zu Java gezogen.
Los geht es mit Arrays. Wie gestern bereits erwähnt, sind Arrays in Scala 0-indiziert, der erste Eintrag liegt also bei Index 0. Im Unterschied zu Java allerdings, wird der Index in Runden klammern angegeben. Was ich gestern noch nicht wusste ist, wie der Mechanismus dahinter funktioniert.
Da in Scala alles ein Objekt ist und es nur sehr wenige Sonderbehandlungen in der Sprache gibt, sind einige syntaktische Specials eingebaut. Wird direkt nach dem Namen eines Objekts eine Klammer aufgemacht, z.B. myarr(0), so wird dieser Aufruf vom Compiler in myarr.apply(0) umgewandelt. Dabei prüft der Compiler auch, ob das angegebene Objekt überhaupt eine Methode apply definiert, und diese auch den richtigen Rückgabetyp hat. Analog führt die Notation myarr(0) = „Neuer Wert“ intern zu myarr.update(0, „Neuer Wert“).
Die bevorzugte Art und Weise ein Array (und andere Datenstrukturen) in Scala zu erzeugen, ist durch eine Factory-Methode:
<td>
<div class="scala codecolorer">
<a href="http://scala-lang.org"><span class="kw1">val</span></a> myarr <span class="sy0">=</span> Array<span class="br0">(</span><span class="st0">'Ich'</span>, <span class="st0">'lerne'</span>, <span class="st0">'Scala'</span><span class="br0">)</span><br /> println<span class="br0">(</span>myarr<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span> <span class="co1">// Druckt "lerne"</span>
</div>
</td>
</tr>
Wie geht das? Analog zu statischen Methoden und Feldern in Java gibt es in Scala sogenannte Compagnon-Objekte zu Klassen. Man definert z.B. eine Klasse „Foo“ und ein „Objekt“ „Foo“. In die Klasse kommen die Methoden, welche dann den verschiedenen Instanzen von Foo zur Verfügung stehen sollen und das Objekt Foo bekommt die die Factory-Methoden. Das gibt es aber definitiv später noch im Detail. Soweit ich es überblicke ist es auf jeden Fall eine schöne Möglichkeit, meine Klassen von statischen Methoden zu trennen.
Wie in Java lassen sich einem Array nur die initial angegebene Zahl von Element einfügen. Ein mit 3 Elementen erzeugtes Array hat also auch auf jeden Fall nur 3 Elemente. Allerdings kann man den an einem Index gespeicherten Wert durch einen anderen Wert ersetzen, selbst wenn das Array als „val“, also in einer unveränderlichen Property angelegt wurde.
Anders als ist in Java ist der Datentyp „List“ nicht die große Schwester von Array mit so tollen Features wie dynamischer Größenänderung. Da Scala den funktionalen Programmierstil propagiert, hält sich List an eben Diesen. Im Gegensatz zu einem Array sind auch die Werte an einer Speicherstelle in der Liste nicht modifizierbar. Alle Operationen auf Listen erzeugen eine neue Liste. Dies ist in etwa vergleichbar mit einem String in Java (und Scala), wo man zwar concat und substring hat, diese Methoden liefern aber jeweils einen neuen String zurück, der ursprüngliche String bleibt unverändert.
Auch schön in Scala sind Tuples. Das sind im Grunde Klassen mit parametrisierbaren Feldern. Die Parametrisierbarkeit bezieht sich dabei auf den Typ der einzelnen Felder. Ein Tuple hat zwischen 1 und 22 Feldern (die 22 wurde willkürlich von den Entwicklern festgelegt). Erzeugt wird so ein Tuple wie folgt:
<td>
<div class="scala codecolorer">
<a href="http://scala-lang.org"><span class="kw1">var</span></a> mytuple <span class="sy0">=</span> Tuple<span class="br0">(</span><span class="st0">'Ich'</span>, <span class="st0">'lerne'</span>, <span class="st0">'Scala'</span>, <span class="nu0">1337</span><span class="br0">)</span>
</div>
</td>
</tr>
Das erzeugte Objekt hat den Typen Tuple4[String, String, String, Int].
Zugriffen werden kann dann auf die Informationen über
<td>
<div class="scala codecolorer">
println <span class="br0">(</span>mytuple.<span class="sy0">_</span>1<span class="br0">)</span><br /> println <span class="br0">(</span>mytuple.<span class="sy0">_</span>2<span class="br0">)</span> <br /> println <span class="br0">(</span>mytuple.<span class="sy0">_</span>3<span class="br0">)</span><br /> println <span class="br0">(</span>mytuple.<span class="sy0">_</span>4<span class="br0">)</span>
</div>
</td>
</tr>
Die Objekte sind z.B. dann sehr praktisch, wenn man mehr als einen Wert aus einer Funktion zurückgeben muss. Unter Java definiert man sich zu diesem Zweck oft ein Java-Bean, in Scala erledigt dass in vielen Fällen die Standardbibliothek. Achja, natürlich sind Tuples keine fest eingebauten Sprachelemente sondern einfach nur in der Klassenbibliothek definiert.
Auch in Scala gibt es natürlich Sets und Maps. Zur Erinnerung: Ein Set entspricht einer Mathematischen Menge. Es kann also jedes Element nur ein mal enthalten. Von daher ist die Semantik identisch mit Java. Ein Map ist eine Zuordnung von einem Schlüssel zu einen Wert. Dabei weißt die Menge der Schlüssel eben eine Set-Semantik auf, der gleiche Wert kann aber, repräsentiert durch verschiedene Schlüssel, mehrfach in einer Map vorkommen.
Durch einen, nennen wir es Trick, ist es in Scala möglich sowohl eine unveränderliche Map bzw. Set zu definieren wie auch eine veränderliche. Erstere ist der Standard, letztere erreicht man durch die Angabe des vollen Klassennamens scala.collection.mutable.Set bzw. scala.collection.mutable.Map. Dazu gibt es auch später im Kurs noch mehr.
Eine Sprachbesonderheit gibt es doch. Betrachten wir den Operator +=. In Java ist das die Kurzform für operand = operand + operand2. In Scala kann das auch eine Methode sein. So gibt es im Gegensatz zu scala.collection.immutable.Set in scala.collection.mutable.Set eine Methode +=, die den ersten Parameter der Methode in das Set einfügt. Die Methode += entspricht also der Methode add von java.util.Set.
Ich muss wohl kaum hinzufügen, dass man Sets und Maps über
<td>
<div class="scala codecolorer">
<a href="http://scala-lang.org"><span class="kw1">var</span></a> myset <span class="sy0">=</span> Set<span class="br0">(</span><span class="st0">'Ich'</span>, <span class="st0">'lerne'</span>, <span class="st0">'Scala'</span><span class="br0">)</span><br /> und myset <span class="sy0">=</span> Map<span class="br0">(</span><span class="st0">'Ich'</span> -<span class="sy0">></span> <span class="co2">'Das</span> bin ich<span class="st0">', '</span>lerne<span class="st0">' -> '</span>Das mache ich gerade<span class="st0">', '</span>Scala<span class="st0">' -> '</span>Das ist eine Programmiersprache<span class="st0">')</span>
</div>
</td>
</tr>
Doch halt! Was macht dieser Pfeil bei der Map? Das ist auch eine Methode, und zwar eine, die jedes Objekt in Scala hat. Der Rückgabewert dieser Methode ist ein Tuple2 mit den Typen der Operanden. Die Angabe 1 -> „Ein String“ lässt sich also auch schreiben als (1).->(„EinString“). Genial!
Nach so viel syntaktischem Zucker, der gar keiner ist, schließt das Kapitel mit einer Einführung (oder Überführung) in die funktionale Programmierung. Ein kleines Programm, welches einer Textdatei Zeilennummern voranstellt (und zwar schön eingerückt), wird entwickelt, und zwar ohne die Benutzung veränderlicher Variablen.
So. Das war mein dritter Tag mit Scala. Im nächsten Kapitel geht es um Klassen und Objekte.