Sonntag, 31. Januar 2010

Closures in Scala

Als funktionale Sprache unterstützt Scala Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). In dem Beitrag über Closures in JavaFXScript hatte ich bereits gezeigt, wie dort Closures definiert und genutzt werden. Wie programmiert man nun Closures in Scala?
// closures1.scala

def zaehlerMitStartwert(startwert: Int): (() => Int) = {
var n = startwert
def nplus1(): Int = { n=n+1; n }
nplus1
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Wir definieren eine Funktion zaehlerMitStartwert(), die den Startwert als Int-Parameter übergeben bekommt. Rückgabe dieser Funktion ist eine Funktion, die keine Parameter hat, aber einen Int-Wert zurückgibt.

Innerhalb der äußeren Funktion legen wir eine Zählvariable n an, da der Übergabeparameter startwert unveränderlich ist. Dann definieren wir eine verschachtelte Funktion nplus1(), die auf die Zählvariable n eins draufzählt und als letzten Ausdruck der Funktion das hochgezählte n zurückgibt. Hier findet der Funktionsabschluss statt - das Binden der Variablen n, die als lokale Variable in der umgebenden Funktion definiert ist. Als letzten Ausdruck in der äußeren Funktion geben wir die Funktion nplus1 als Ergebnis zurück.

Das ganze geht auch etwas kürzer und "funktionaler", wenn man die innere Funktion nicht explizit definiert, sondern als letzten Ausdruck der äußeren Funktion gleich ein entsprechendes Funktionsliteral hinschreibt:
// closures2.scala

def zaehlerMitStartwert(startwert: Int) = {
var n = startwert
() => { n=n+1; n }
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Beide Skripte liefern dieselbe Ausgabe:
HeartOfGold:~ much$ scala closures2.scala
11
21
22
12
Wenn man den Scala-Interpreter mit scala -savecompiled closures2.scala aufruft, erhält man ein JAR-Archiv, in dem man sich die generierten Java-Bytecode-Dateien anschauen kann. In diesem Fall werden vier class-Dateien erzeugt.