JavaFX Script (die Programmiersprache für Suns neue
RIA-Technologie
JavaFX) ist eine objektorientierte, deklarative und funktionale Programmiersprache.
Als funktionale Sprache unterstützt sie Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). Ersteres bedeutet, dass Funktionen selber Werte sind – sie können also als Parameter übergeben und zurückgegeben werden. Letzteres erlaubt den Funktionswerten, dass sie sich den Zustand ihrer Umgebung (die lokalen Variablen) bei ihrer Erzeugung merken können.
Für viele sind Closures seltsame Konstrukte und ihre Einsatzmöglichkeiten nicht offensichtlich. Daher im Folgenden ein kleines, relativ leicht verständliches Beispiel, in dem mehrere Zähler mit individuellen Startwerten erzeugt und benutzt werden:
// closure.fx
function zaehlerMitStartwert(startwert: Integer) {
var n = startwert;
return function(): Integer { return n++ }
}
var next1 = zaehlerMitStartwert(10);
var next2 = zaehlerMitStartwert(20);
println( next1() ); // 10
println( next2() ); // 20
println( next2() ); // 21
println( next1() ); // 11
Wer das Beispiel ausprobieren möchte, installiert sich das
JavaFX 1.2 SDK und nutzt die Kommandozeile (oder
NetBeans oder
Eclipse mit dem JavaFX-Plugin):
Straylight:~ much$ javafxc closure.fx
Straylight:~ much$ javafx closure
10
20
21
11
Die ausgegrauten Elemente sind nicht wirklich notwendig und sollen nur das Skript für Java-Programmierer leichter verständlich machen. "return" ist an beiden Stellen optional, da der letzte Ausdruck in einer Funktion gleichzeitig deren Ergebnis definiert. Der Rückgabetyp ":Integer" der inneren, anonymen Funktion ist optional, da aus dem Datentyp des Ergebnisses der Rückgabetyp durch
Typinferenz ermittelt werden kann.
Trotz (bzw. gerade wegen) dieser impliziten Typisierung ist JavaFX Script im Gegensatz zu
Skriptsprachen wie JavaScript statisch und streng typisiert. Bereits der Compiler ermittelt also die Datentypen und Signaturen von Variablen und Funktionen, sofern sie nicht explizit angegeben sind. Im Beispiel hat die Variable
n also den Datentyp
Integer, die Variablen
next1 und
next2 haben den Typ
function():Integer und
zaehlerMitStartwert hat den Typ
function(:Integer):function():Integer :-)
Wie funktioniert das Skript? Beim Aufruf der Funktion
zaehlerMitStartwert wird eine Funktion zurückgegeben, die bei jedem Aufruf die Variable
n um eins erhöht zurückgibt. Obwohl die Variable
n zur äußeren Funktion gehört und damit beim Aufruf der zurückgegebenen Funktion mit
next1() bzw.
next2() eigentlich gar nicht mehr vorhanden ist, merkt sich die innere Funktion die lokale Variable separat für jede zurückgegebene innere Funktion – und genau das macht sie zur Closure.
Man kann sich Closures als Objekte vorstellen, die aus einer einzigen Methode/Funktion bestehen und wie Objekte zusätzlich einen Zustand haben. Schön sehen kann man dies an den generierten Java-Bytecode-Klassendateien:
closure.class und
closure$1.class. Die innere, anonyme Funktion wird für die JVM also einfach als innere, anonyme Java-Klasse
closure$1.class abgebildet.
Closures sind prima geeignet, um damit z.B. Event-Handler zu definieren, denen man zusätzliche Informationen mitgeben kann (bei Farb-Setz-Buttons in einem Grafikprogramm beispielsweise die zu setzende Farbe). Dadurch kann man häufig auf das Schreiben von Event-Handler-Klassen verzichten, auch wenn dies in JavaFX Script ebenfalls möglich ist.
Vielleicht hat man es gemerkt: Ich halte JavaFX Script trotz des Namens ganz und gar nicht für eine Skriptsprache. Meines Erachtens wurde die Sprache vor allem deshalb so genannt, um zu zeigen, dass man damit in Wettbewerb zu Skriptsprachen wie Ruby tritt, die als agil und produktiv empfunden werden. JavaFX Script zeigt dabei sehr schön, dass sich Produktivität und statische, strenge Typisierung überhaupt nicht ausschließen müssen.