Es geht selbstverständlich nicht darum, alles bis ins letzte Detail zu erklären oder einen vollständigen Überblick über die Sprachfeatures zu geben. Stattdessen sollen eine Reihe von Sprachkonstrukten vorgestellt werden, die ich cool finde – vielleicht kommt ja etwas von meiner Begeisterung rüber.
Alles ist ein Objekt
Zunächst einmal ist in Scala alles ein Objekt, und man kann auf allem Methoden definieren und aufrufen. Java ist an dieser Stelle noch etwas mehr der maschinennahen Kultur der Programmiersprache "C" verbunden: Primitive Datentypen und Arrays haben eine Sonderrolle. Mit Autoboxing (der impliziten Umwandlung z.B. von int in java.lang.Integer) ist das seit Java 1.5 etwas aufgeweicht, aber die Unterscheidung bleibt doch bestehen. Scala ist an dieser Stelle konsequenter und damit einfacher. Es gibt das ganze Konzept primitiver Typen überhaupt nicht. Jede Zahl, die im Quelltext steht, ist ein Objekt (Listing 1).
val summe1 = 1+2// nur andere Schreibweiseval summe2 = 1.+(2)// 'to' ist auch eine Methodefor (i <- 1 to 10)println (i)
Und auch die eingebauten Operatoren wie "+" oder "-" haben keine Sonderrolle, sondern sie sind einfach Methoden. Man kann in Scala den Punkt und die Klammern weglassen, wenn man eine Methode mit genau einem Parameter aufruft, und auf diese Weise die gewohnte Infix-Notation verwenden. Auch die Schreibweise for (i <- 1 to 10) für eine Schleife über die Zahlen von 1 bis 10 beruht auf der Methode to, die auf dem Typ Int definiert ist und einen Iterator zurückliefert. Bei manchen mag die Vorstellung, dass alles Objekte sind, Sorgen um die Performance auslösen. Deshalb hier der Hinweis, dass Scala unter der Oberfläche so gut es geht die primitiven Konstrukte der JVM verwendet. Oder anders gesagt: Die Zahl 1 wird in Scala genau wie in Java als 32-Bit-Wort abgebildet – nur dass man sie mit Scala als Objekt behandeln kann.
Eine Klasse
Doch wenden wir uns jetzt konkret dem Schreiben von Klassen in Scala zu. In bewährter Manier fangen wir mit einem konkreten Beispiel an, und zwar in Anlehnung an "Programming in Scala" mit den rationalen Zahlen, also Brüche (Listing 2a).
package rationalclass Rational (z: Int, n: Int) {require (n != 0)val zaehler = zval nenner = noverride def toString = z + "/" + nprintln ("neuer Bruch: " + this)}
Am Anfang einer Scala-Datei kann – genau wie in Java – eine optionale Package-Anweisung stehen. Die Klassendefinition selbst beginnt mit dem wohlbekannten Schlüsselwort class. Im Unterschied zu Java haben aber in Scala per Default die Elemente public als Sichtbarkeit, dafür muss man also nichts extra hinschreiben.
Der erste große Unterschied zu Java, der dann ins Auge springt, besteht in den beiden Parametern z (für "Zähler") und n (für "Nenner"), die die Klasse hat. Diese beiden Parameter sind – zusammen mit dem Code in der Klasse, zu dem wir gleich kommen – der so genannte primäre Konstruktor der Klasse. Jede Scala-Klasse hat genau einen solchen primären Konstruktor, und für jede neue Instanz wird er direkt oder indirekt aufgerufen. Konkret heißt das, dass jede unserer rationalen Zahlen mit einem Zähler und Nenner erzeugt wird. Die beiden Parameter sind so etwas wie lokale Variablen für den primären Konstruktor. Der gesamte Code der Klasse sieht sie und kann sie verwenden, sie sind aber keine Attribute der Klasse und deshalb von außen nicht sichtbar. Beim Erzeugen einer Instanz wird der Inhalt der Klasse "abgearbeitet", in etwa so, als ob er ein Skript wäre. Code wird direkt ausgeführt, und Variablen- bzw. Funktionsdefinitionen werden zu Attributen, bzw. Methoden. Die Implementierung des primären Konstruktors beginnt mit einem Aufruf von require, der sicherstellt, dass der Nenner des neu erzeugten Bruchs nicht 0 ist. Das dient zur Überprüfung von Preconditions und wirft eine Exception, wenn die Bedingung nicht erfüllt ist.




