[Closures] Introductie
By: Jan-Kees van Andel, 29 August 2008Closures, één van de meest bediscussieerde onderwerpen van de afgelopen paar jaren in de Java wereld. Deels een hype, deels bieden closures meerwaarde voor Java development. Ik ga niet meedoen met alle discussies waarom ze (niet) gewenst zijn, maar het is een feit dat het mogelijkheden biedt qua API design. In dit stuk hoop ik a) de mystieken van closures iets duidelijker te maken en b) wat inzicht te geven in de huidige closures oorlog bij Java.
Closures
Wat is een closure? WikiPedia (http://en.wikipedia.org/wiki/Closure_(computer_science)) heeft de volgende nietszeggende definitie: “In computer science, a closure is a function that is evaluated in an environment containing one or more bound variables. When called, the function can access these variables.”. Hoewel deze definitie klopt, is hij niet echt duidelijk. Waar komt het op neer?
Bij een closure wordt een functie uitgevoerd in een andere context dan waarin deze wordt gecreëerd. Deze zogenaamde “function context” wordt bij het creëeren van de functie bij de referentie naar de functie opgeslagen. Dit betekent dat als iemand deze referentie te pakken krijgt en de functie aanroept, de variabelen uit de context waarin de functie gemaakt is, beschikbaar zijn.
Voordat ik concreter wordt, wil ik nog even aangevan dat closures niet nieuw zijn. In vrijwel elke mainstream taal zit een soortgelijke constructie. Ook in Java, namelijk met anonymous inner classes, maar andere talen, zoals Smalltalk, JavaScript en Ruby bieden veel meer flexibiliteit.
Nog steeds nietszeggend? Dan maar een codevoorbeeld (JavaScript):
<html>
<head>
<script type="text/javascript">
function initPage() {
var counter = 0;
window.onclick = function() {
alert("Click #" + ++counter);
};
}
window.onload = initPage;
</script>
</head>
<body></body>
</html>
Wat gebeurt hier? Om te beginnen zijn functies in JavaScript first class objecten, in tegenstelling tot in Java, waarin methoden altijd onderdeel van een object zijn. Dit betekent onder andere dat je naar een functie kunt refereren, of deze referentie in een variabele kunt stoppen om deze daarna rond te gooien. Dit kun je zien aan de regel “window.onclick = …” waarin een object van het type function aan de onclick property van het window object toegekend wordt.
Wat (hopelijk) ook opvalt is dat er een function in een andere function gedeclareerd wordt. In dit voorbeeld spreken we van een anonymous inner function. Dit is een belangrijk detail, aangezien dit voor de JavaScript interpreter betekent dat er een closure gecreeerd moet worden. Wat betekent dit?
Kort gezegd betekent een closure dat bij de referentie naar de anonymous inner function, alle variabelen uit de enclosing scope bewaard blijven. Vandaar de naam closure. Deze variabelen vormen de function context welke vanaf nu een deel van de functie geworden. Elke keer als je deze functie aanroept, zijn de variabelen in de function context beschikbaar.
Wat is het nut dan van deze closure? Nou, de variabele “counter” heeft een function scope en verdwijnt op het moment dat de functie eindigt. Bij een event handler zoals in bovenstaand voorbeeld betekent dit dus dat de variabele op het moment van de klik niet bruikbaar is, aangezien het click-event niet in dezelfde stack plaatsvindt. Dit betekent dus dat je zonder closures een globale variabele nodig hebt om een simpel tellertje te maken. Met closures heb je deze beperking niet, want de variabele counter blijft bewaard en de ++ operator werkt de variabele in de function context bij, zodat het ook een echte teller is.
Conclusie
Closures bieden dus de mogelijkheid om stack confined variabelen te bewaren over meerdere stacks heen en zijn daardoor dus zeer geschikt voor event handlers. Dat is ook de reden dat ze in JavaScript veel gebruikt worden. JavaScript wordt voornamelijk gebruikt voor het koppelen van event handlers aan buttons etc. Daarnaast biedt het een mooie compacte syntax.
Volgende keer kijken we naar de Java closures initiatieven.


1 September 2008 om 11:37 am
Het kan aan mij liggen, maar volgens mij moet het dit zijn:
Daarnaast krijg ik van Firefox 3 / FireBug de melding dat ‘privateVariable’ undefined is. Dit klopt volgens mij ook wel omdat het een referentie betreft naar een globale variable.
1 September 2008 om 1:49 pm
2x true, ik wilde de code nog wat mooier maken, maar dat was een slecht plan. Nog geluk dat het window.onclick is, anders had de code niet eens gewerkt…
Code is aangepast.