Teil 1: Entwicklungsumgebung und Objektorientierung

Game of Life mit Scala – das Tutorial

Heiko Seeberger

Inzwischen sollte es sich bei fast allen Java-Entwicklern herumgesprochen haben, dass Scala eine sehr zukunftsträchtige Sprache für die Java Virtual Machine ist. Daher lassen wir jetzt einmal die ganze Prosa beiseite und machen uns die Hände schmutzig, um selbst ein Gefühl dafür zu bekommen, wie sich Scala eigentlich anfühlt. In diesem zweiteiligen Tutorial bauen wir Schritt für Schritt eine Beispielanwendung und lernen dabei viele wichtige Grundlagen der Sprache kennen.

Ganz am Anfang steht, wie immer in solchen Tutorials, die Frage nach einem geeigneten Beispiel. Es sollte durchaus „sexy“ sein, am besten sogar mit einer grafischen Oberfläche. Jedoch darf es keinesfalls zu komplex sein, sonst lenkt es vom eigentlichen Zweck ab und sprengt vielleicht sogar den Rahmen. Außerdem sollte es alleine mit Scala-Bordmitteln bearbeitet werden können, d. h. mit Ausnahme von Testwerkzeugen ohne zusätzliche Abhängigkeiten. Denn schließlich wollen wir Scala unter die Lupe nehmen und nicht Lift [1], Akka [2] oder ein sonstiges Scala-Framework.

Daher haben wir uns für eine idiomatische und einfache Implementierung des grandiosen Game of Life [3] entschieden. Wer das noch nicht kennt, dem empfehlen wir wärmstens, sich unter der angegebenen Quelle zu informieren, denn diese einfache Simulation biologischen Lebens ist hochinteressant. Wir legen hier natürlich keinen Wert darauf, eine besonders performante oder gar verteilte Lösung zu entwickeln oder algorithmische Kunststückchen zu vollbringen. Vielmehr wollen wir auf einfache Weise möglichst viel davon zeigen, was Scala so auf dem Kasten hat. Apropos Kasten: Die zusammengefassten Spielregeln für das Game of Life befinden sich im gleichnamigen Kasten.

Game of Life: Spielregeln

Unser Spielfeld ist ein unendliches Gitter. Jedes Gitterquadrat stellt eine Zelle dar, die entweder tot oder lebendig sein kann. Die Gesamtheit aller Zellen zu einem bestimmten Zeitpunkt nennen wir Generation. Wir ermitteln die nächste Generation auf Basis der aktuellen anhand der folgenden Regeln:

  • Eine lebendige Zelle mit zwei oder drei lebendigen Nachbarn bleibt am Leben
  • Eine lebendige Zelle mit weniger als zwei lebendigen Nachbarn stirbt an Einsamkeit
  • Eine lebendige Zelle mit mehr als drei lebendigen Nachbarn stirbt an Überbevölkerung
  • Eine tote Zelle mit genau drei lebendigen Nachbarn wird wieder geboren

Wir werden das Beispiel im Folgenden Schritt für Schritt entwickeln. Das gesamte Beispielprojekt ist Open Source unter der Eclipse Public License [4] und kann unter http://github.com/weiglewilczek/gameoflife eingesehen oder heruntergeladen werden. Wer Git verwendet, kann sogar anhand der Commit-Historie alle Schritte einzeln nachvollziehen.

Die Entwicklungsumgebung

Eine andere wichtige Frage lautet: Wie soll unsere Entwicklungsumgebung aussehen? Java-Entwickler sind von mächtigen IDEs wie Eclipse, IntelliJ IDEA oder Netbeans sehr viel Komfort gewohnt. Auch für Scala gibt es seit der Version 2.8 endlich recht brauchbare Plug-ins für die „großen“ IDEs. Wir wollen hier jedoch keine IDE voraussetzen, um erst gar nicht in die oft allzu hitzig geführte Debatte zu geraten, welche IDE die beste sei. Außerdem wird unser Beispiel, ganz typisch für Scala, nur wenig Code benötigen, sodass wir ohne Probleme mit einem Texteditor zurechtkommen. Wer das Beispiel nachvollziehen möchte, darf selbstverständlich eine IDE verwenden; wir machen das nur nicht zur Voraussetzung.

Doch wie kompilieren wir unser Beispiel eigentlich? Wie testen wir? Wie führen wir es aus? Dazu verwenden wir das Build-Werkzeug SBT [5] (Simple Build Tool) und schlagen damit gleich zwei Fliegen mit einer Klappe. Erstens tragen wir der Tatsache Rechnung, dass in „echten“ Projekten meist ein Build-Werkzeug zum Einsatz kommt. Zweitens ist SBT einfach unglaublich gut und einfach, wenn man Ant und Maven gewöhnt ist. SBT ist selbst in Scala geschrieben und berücksichtigt einige Besonderheiten von Scala. Insbesondere ist der Build trotz des recht langsamen Scala-Compilers schnell, der Aufruf der interaktiven Konsole (REPL) mit komplettem Projektklassenpfad einfach und Cross-Building gegen mehrere Scala-Versionen möglich. Viele Projekte wie Lift oder Akka setzen bereits auf SBT oder planen den Umstieg. Selbstverständlich kann das Beispiel auch ohne SBT kompiliert und ausgeführt werden, z. B. mit einer IDE oder einfach mit den Kommandozeilenwerkzeugen. Wer sich dafür entscheidet, der kann den nächsten Abschnitt gerne überspringen.

SBT-Projekt anlegen

Bevor wir loslegen, müssen wir SBT „installieren“. Da SBT nur aus einem JAR besteht, ist das denkbar einfach: Wir laden die aktuelle Version sbt-launch-0.7.4.jar von der SBT-Website unter Downloads [6] herunter und erstellen ein Startskript wie auf der SBT-Homepage unter Setup [7] beschrieben. Unter Mac OS sieht das exemplarisch so aus: java -Xmx1024M -jar sbt-launch-0.7.4.jar „

psenv::pushli(); eval($_oclass[„“]); psenv::popli(); ?>

@“. Danach legen wir als Erstes ein Projektverzeichnis an, z. B. gameoflife, und begeben uns in der Shell dorthin. Dann legen wir mit SBT ein Projekt an, indem wir das SBT-Startskript aufrufen und die gestellten Fragen folgendermaßen beantworten:

gameoflife$ sbt
Project does not exist, create new project? (y/N/s) y
Name: gameoflife
Organization: com.weiglewilczek.gameoflife
Version [1.0]: 
Scala version [2.7.7]: 2.8.0

Wie wir anhand der daraufhin erscheinenden Ausgaben erkennen können, lädt SBT u. a. Scala 2.8.0 herunter, d. h. wir müssen uns gar nicht um die Scala-Distribution kümmern. Die anderen Downloads benötigt SBT selbst, so auch Scala 2.7.7.

Wenn wir SBT ohne Argumente aufrufen, gelangen wir in die SBT-Konsole, einen interaktiven Modus, in dem wir Kommandos wie exit, compile, test oder run aufrufen können. Die ersten sind hoffentlich selbsterklärend: Mit run wird ein Singleton Object mit einer main-Methode gesucht und ausgeführt. Besonders interessant: Wenn wir die „Tilde“ voranstellen, gelangen wir in einen Modus, in dem SBT auf Änderungen im Dateisystem wartet und dann automatisch das entsprechende Kommando ausführt. So können wir z. B. mit ~ compile kontinuierlich kompilieren. Für weitere Kommandos und Details sei auf die hervorragende Dokumentation auf der SBT-Homepage verwiesen.

Nach Ausführen von test sieht unser Projektverzeichnis wie in Abbildung 1 dargestellt aus. Wer schon einmal mit Maven gearbeitet hat, dem dürfte das src- und das target-Verzeichnis bekannt vorkommen, wobei unter target zusätzlich noch die Scala-Version(en) erscheinen, gegen die gebaut wird. Das ist wichtig, denn verschiedene Scala-Versionen sind leider (noch) binär inkompatibel. Das project-Verzeichnis enthält u. a. die Konfiguration für unser Projekt sowie die herunter eladenen Dateien, z. B. Scala 2.8.0. Im lib-Verzeichnis können wir Bibliotheken ablegen, die automatisch zum Klassenpfad hinzugefügt werden. Selbstverständlich beherrscht SBT auch „Managed Dependencies“ analog zu Maven, aber das brauchen wir hier gar nicht.

Abb. 1: SBT-Projektstruktur
Geschrieben von
Heiko Seeberger
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.