Categories: Programming, Java
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.8.
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.
What the examples below show is that a closure (ie some logic plus variables) can be stored, and invoked later. Unlike a simple function-pointer or callback object, variables other than local variables within the closure function/method are still accessable.
Closures can get quite tricky in the details. There is an excellent (though rather long) description on wikipedia.
Javascript Version
Here is a simple closure example implemented in javascript.
<html>
<head>
<script>
var baseStrings = ["Day", "Month", "Year"]
var postfix = ".";
function makeStringTransformer(prefix) {
// return a closure that "captures" the prefix and postfix values
return function(s) {
return prefix + s + postfix;
}
}
function map(src, closure) {
var out = [];
for(index in src) {
out[out.length] = closure(src[index]);
}
return out;
}
function showList(src) {
document.write("<p>");
for(o in src) {
document.write(src[o]);
document.write(" ");
}
document.writeln("</p>");
}
var closure1 = makeStringTransformer("Previous ");
var closure2 = makeStringTransformer("Next ");
var mapped1 = map(baseStrings, closure1);
showList(mapped1);
var mapped2 = map(baseStrings, closure2);
showList(mapped2);
postfix = "!";
var mapped3 = map(baseStrings, closure2);
showList(mapped3);
</script>
</head>
</html>
Generated Output
Previous Day. Previous Month. Previous Year.
Next Day. Next Month. Next Year.
Next Day! Next Month! Next Year!
Closure Features
The magic in this little example is that the thing returned from the makeStringTransformer function is a closure - an anonymous function plus sufficient information for the function to access variables that are not local to the function. A closure can be stored as a variable, and executed at any later time - just a few lines later in this example, but in a real program they could be run in response to a user button-click or a timer expiring or similar events.
At the time that the closures execute, the “prefix” value no longer exists as such - it disappeared (went out of lexical scope) as soon as the makeStringTransformer function returned.
The postfix variable still exists, and the last line of output shows that the closure has a “live” reference to the variable, rather than having just cached its value when the closure was created.
Java Equivalent - Explicit Version
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.
In java 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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Calendar;
import java.util.List;
import java.text.SimpleDateFormat;
// Define a "function object" that takes one param and returns one value.
// Alas, a different interface type is needed for different #s of params.
interface ClosureWith1Param<OUT, IN> {
OUT invoke(IN param1);
}
class StringTransformerClosure implements ClosureWith1Param<String, String> {
private String prefix;
private StringBuilder postfix;
StringTransformerClosure(String prefix, StringBuilder postfix) {
this.prefix = prefix;
this.postfix = postfix;
}
@Override
public String invoke(String in) {
return prefix + in + postfix;
}
};
public class ClosureExample1 {
private static List<String> baseStrings = Arrays.asList("Day", "Month",
"Year");
private static StringBuilder postfix = new StringBuilder("."); // mutable
// string
private static ClosureWith1Param<String, String> makeStringTransformer(
String prefix) {
// return a "closure" that "captures" the prefix and postfix values
return new StringTransformerClosure(prefix, postfix);
}
public static List<String> map(List<String> src,
ClosureWith1Param<String, String> closure) {
ArrayList<String> out = new ArrayList<String>(src.size());
for (String str : src) {
out.add(closure.invoke(str));
}
return out;
}
private static void showList(List<?> in) {
for (Object o : in) {
System.out.print(o);
System.out.print(" ");
}
System.out.println();
}
public static void main(String[] args) throws Exception {
ClosureWith1Param<String, String> closure1 = makeStringTransformer("Previous ");
ClosureWith1Param<String, String> closure2 = makeStringTransformer("Next ");
List<String> mapped1 = map(baseStrings, closure1);
showList(mapped1);
List<String> mapped2 = map(baseStrings, closure2);
showList(mapped2);
postfix.setLength(0);
postfix.append("!");
List<String> mapped3 = map(baseStrings, closure2);
showList(mapped3);
}
}
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 a concrete implementation that includes the desired code as a method, and has a constructor whch grabs copies of the non-local vars it references.
Java Equivalent - Inner Class Version
Java anonymous inner 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:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Calendar;
import java.util.List;
import java.text.SimpleDateFormat;
public class ClosureExample2 {
private static List<String> baseStrings = Arrays.asList("Day", "Month",
"Year");
private static final StringBuilder postfix = new StringBuilder("."); // mutable
// string
interface ClosureWith1Param<OUT, IN> {
OUT invoke(IN param1);
}
private static ClosureWith1Param<String, String> makeStringTransformer(
final String prefix) {
// return a "closure" that "captures" the prefix and postfix values
return new ClosureWith1Param<String, String>() {
public String invoke(String in) {
return prefix + in + postfix;
}
};
}
public static List<String> map(List<String> src,
ClosureWith1Param<String, String> closure) {
ArrayList<String> out = new ArrayList<String>(src.size());
for (String str : src) {
out.add(closure.invoke(str));
}
return out;
}
private static void showList(List<?> in) {
for (Object o : in) {
System.out.print(o);
System.out.print(" ");
}
System.out.println();
}
public static void main(String[] args) throws Exception {
ClosureWith1Param<String, String> closure1 = makeStringTransformer("Previous ");
ClosureWith1Param<String, String> closure2 = makeStringTransformer("Next ");
List<String> mapped1 = map(baseStrings, closure1);
showList(mapped1);
List<String> mapped2 = map(baseStrings, closure2);
showList(mapped2);
postfix.setLength(0);
postfix.append("!");
List<String> mapped3 = map(baseStrings, closure2);
showList(mapped3);
}
}
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 in the first example.
Referencing Immutable and Primitive Objects From Closures
You will have noticed that in the Java version it was necessary to use a mutable StringBuilder object in order for the existing closure to see changes to the postfix value.
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 “postfix” value change. And what is held by the closure cannot be the “name” of the variable, because the closure can still access the “prefix” value even after that function has returned, ie those names are no longer valid in the context of the caller.
In fact, a javascript function’s lexical context is simply a map of (name->value)
, and every variable reference is effectively a lookup into the map by name. There is a chain of these context objects - one for each nested function call. When the closure is created, it simply stores a pointer to the current lexical context of the caller - ie the entire callstack. From the closure’s point of view it is as if the enclosing function had never returned. Most compiled languages do not do this sort of thing (not very efficient spacewise); they do not do variable lookup at runtime, and therefore act like the Java code examples.
The fact that javascript closures capture the entire frame can easily be proved, by doing an “eval” inside a closure to look up a variable by name..
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 the closure holds a reference to the entire context in which it was created, and if this contains references to objects that are no longer used, they still cannot be garbage-collected while the closure exists.
Summary
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.
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. ↩