Closures For Java Programmers
Introduction
Closures are a code feature available in many languages, including:
- c#
- ruby
- javascript
- lisp, scheme
And they are hopefully coming to Java in version 1.7.
Understanding closures isn’t hard, but the way that variables can be “captured” by a closure can be confusing at first. To demonstrate how this works, this article shows how something similar to a closure would appear if manually implemented in java code.
Javascript Version
Here is a simple closure example implemented in javascript.
var shopNames = ["books unlimited", "books everywhere"];
var year = "2010";
function forEachShop(closureToRun) {
var index;
for(index in shopNames) {
// note: closureToRun is a variable whose *value* is a closure, but we can use it here like
// a function, causing the closure code to be executed.
closureToRun(shopNames[index]);
}
}
function showBook() {
var article = "book";
var price = 12;
// create a closure, ie an anonymous function which also "captures" some non-local variables .
var showRetail = function(shopName) {
document.writeln(shopName + ' ' + year + ' article=' + article + ' price=' + price + '<br/>');
}
price = 15;
forEachShop(showRetail);
return showRetail;
}
var closure = showBook();
year = "2011";
forEachShop(closure);
Generated Output
books unlimited 2010 article=book price=15
books everywhere 2010 article=book price=15
books unlimited 2011 article=book price=15
books everywhere 2011 article=book price=15
Closure Features
The magic in this little example is that
- the showRetail function was able to access variables that were declared outside it;
- the function can be passed to some other function (eg forEachShop) that chooses when to invoke it;
- that even after the function that created the closure returns, the closure can still access variables from the scope it was declared in.
Actually, it’s not magic at all; see below.
Java Equivalent
A true closure has two parts:
- It is just a method, not a class
- It “captures” variables from enclosing scopes for use when invoked later
In java it is currently impossible to emulate (1). The best we can do is to create an interface with a single method which works but lacks the elegance of a true closure.
We can implement (2) reasonable effectively, although it takes a fair bit of boilerplate code. See later for a way to reduce the ugliness by using an anonymous class + final variables.
import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;
interface ClosureWithOneArg<P> {
void invoke(P param1);
}
class ShowRetail implements ClosureWithOneArg<String> {
private Calendar year;
private String article;
private int price;
ShowRetail(Calendar year, String article, int price) {
this.year = year;
this.article = article;
this.price = price;
}
public void invoke(String shopName) {
System.out.println(shopName + " " + year.get(Calendar.YEAR) + " article=" + article + " price=" + price);
}
}
public class Main {
private static String[] shopNames = {"books unlimited", "books everywhere"};
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
private static Calendar year = Calendar.getInstance();
public static void forEachShop(ClosureWithOneArg<String> closure) {
for(String shopName : shopNames) {
closure.invoke(shopName);
}
}
public static ClosureWithOneArg<String> showBook() {
String article = "book";
int price = 12;
ShowRetail showRetail = new ShowRetail(year, article, price);
price = 15;
forEachShop(showRetail);
return showRetail;
}
public static void main(String[] args) throws Exception {
year.setTime(dateFormat.parse("2010"));
ClosureWithOneArg<String> closure = showBook();
year.add(Calendar.YEAR, 1);
forEachShop(closure);
}
}
As is clear from this, a “closure” is just a way of:
- automatically creating a suitable interface class for the code to be invoked1;
- automatically figuring out what non-local variables are referenced from the closure’s code;
- creating an “impl” object that includes the code as a method, and grabs copies of the non-local vars it references.
While not super-complex, closures are extremely useful. In particular, the ability to create a small snippet of code that can be passed to some other object to run when needed is a very powerful tool. Java’s native inner class or anonymous inner class features just don’t quite go far enough; as you can see from the above, the amount of extra code needed to capture necessary variables and to create an appropriate interface makes this technique just too clumsy for frequent use.
Java anonymous classes do have a feature that is not taken advantage of above: it can reference “final” variables. So we could rewrite the showBook method above as:
// Main.year declared final...
public static ClosureWithOneArg<String> showBook() {
final String article = "book";
final int price = 12;
ClosureWithOneArg<String> showRetail = new ClosureWithOneArg<String>() {
public void invoke(String shopName) {
System.out.println(shopName + " " + year.get(Calendar.YEAR) + " article=" + article + " price=" + price);
}
};
forEachShop(showRetail);
return showRetail;
}
This form would of course be the preferred form when writing this kind of callback code in java; it was not used in the first example because it isn’t so clear what is going on behind the scenes. In practice, the java compiler will generate the same code we manually wrote to copy the year/article/price references.
Referencing Immutable and Primitive Objects From Closures
You will note that the output from the Java version is not quite the same as from the Javascript version : the change in the “price” field done in method showBook is not picked up in the java version (price still shows as 12). However the year change done in main() is picked up. The cause is obvious: “price” is a primitive value, and so when that value is copied, the copy is “detached” from the original. However “year” is a mutable object, and class ShowRetail just holds another reference to the same instance, so changes in the original are seen by the closure whenever it gets run. If Main.year were reassigned to be a different Calendar object, rather than just updating the original object, then again the change would not be seen in our “faked” closure version.
For scripting languages like Javascript, this problem does not occur. Quite how this works is interesting; clearly what is being held by the closure is not a reference to the actual variable value because even in Javascript a String is immutable, yet we see the “year” value change. And what is held by the closure cannot be the “name” of the variable, because the closure can still access article/price even after that function has returned, ie those names are no longer valid. My best guess is that because of its “dynamic typing”, a javascript variable is actually a descriptor which holds a (type, actualValue) pair, and the current value (eg “2011”) is stored in the actualValue. Assigning a new value to the var then updates actualValue (and maybe type) of the existing object; thus for a string variable the actualValue is immutable but the descriptor is not. And a closure holds a reference to the “descriptor”, and therefore sees changes in “immutable” objects. The equivalent in Java would be to wrap every object in a mutable “Holder” wrapper, and then for the closure to keep references to the “Holder” object, not the underlying value; this would be effective but again rather inelegant.
Scopes of Captured Variables
When a closure holds a reference to a variable, of course it would be very bad if that variable no longer existed at the time the closure ran. For Java this is never a problem, as all variables are allocated on the “heap”, and only removed via garbage collection when the number of references drops to zero, which won’t happen as long as the closure itself exists. Closures are also supported in some c-like languages, and in these cases there needs to be some mechanism to prevent or handle references to on-stack variables from closures.
Memory Leak Issues
Beware that closures can be a source of memory leaks. Often closures are stored in collections or member fields for later use (eg a closure to run if a specific button is clicked). However it is sometimes hard to spot exactly which non-local variables a closure references, and of course those variables (and everything they reference) cannot be freed while the closure still exists.
Footnotes
-
Typically a closure is stored in a variable, eg:
Closure m = (…some code …)
In most languages that support closures, invoking the closure code is then simply something like
m(args);. The java example in this article usesclosure.invoke(args), ie invokes the code via the name declared on an interface it implements, which is rather clumsy.↩