Using Closures in Java
In the last years, fuctional programming languages such as Haskel, F#, and clojure, have gained acceptance among programming enthusiasts. They allow a concise style of programming that is not easy to replicate with imperative languages.
Much of the power of functional programming languages is linked to the existence of closures. A closure is a way of binding variables to function definitions, so that you can refer to the variable later from the body of the function. The way the concept works is similar to fields in an object, but without requiring the existence of a class. This means that, in general, functions can have the same power of classes in an OO language.
For example, in common lisp one can write something like this:
(defun f () (let ((x 0)) (function (lambda () (print (incf x)))))) (defvar add (f)) (funcall add) (funcall add)
Here, we are creating a function f
that returns a function (as defined by the lambda form). However, the returned function increments the value of x, which is a variable internal to the function f
itself. Now, every time we call add, we are in fact incrementing and printing the value of x
. Thus, the result of the execution of these lines is just
1 2
In this example, the function add has access to the internal variable x, defined in the let scope. Notice that, each time we call “add” we are incrementing that internal variable, even though the function f has ended — now, that is a trick!
Doing something like this is a non-functional language requires the help of OO. In Java, it gets a little ugly. In the following, I show how we can define a general interface for a unary function. This interface can be implemented so that some variables are bound, in a way similar to a closure.
import java.util.ArrayList; import java.util.List; public class Test { interface UnaryFunc<T> { void exec(T t); } class ListIt<T> { List<T> l_; public ListIt(List<T> l) { l_ = l; } void apply(UnaryFunc<T> f) { for (T e : l_) { f.exec(e); } } } private UnaryFunc<Integer> getClosure(final int x) { final int[] total = {0}; return new UnaryFunc<Integer>() { public void exec(Integer t) { total[0] += (t + x); System.out.println("x val: " + x + " t: " + t + " total: " + total[0]); }}; } protected void useClosure(UnaryFunc<Integer> f) { List<Integer> x = new ArrayList<Integer>(); x.add(2); x.add(4); x.add(5); x.add(6); new ListIt<Integer>(x).apply(f); } protected void callClosureAcceptingMethod() { useClosure(getClosure(20)); } public static void main(String []args) { Test t = new Test(); t.callClosureAcceptingMethod(); // print: // x val: 20 t: 2 total: 22 // x val: 20 t: 4 total: 46 // x val: 20 t: 5 total: 71 // x val: 20 t: 6 total: 97 } }
What is going on here? The main action happens on method getClosure. The returned object is just the representation of a function. The variable total is being hold by the function object, and each time the function is executed, it adds the given value t. Also, notice that not only a local variable can be part of the closure, but also the parameter x, which is also added each time the function object is called.
Finally, notice that only a final variable can be used as part of the closure. This is a limitation of Java. For that reason, if we need a place to hold mutable data, we need to declare an array with one position (as we did with the total variable). It is a nuisense, but not really difficult to remember.
What about C#?
The current version of C# is much more friendly to users of closures. Moreover, the above example can be written much more easily — C# simplifies all that by using delegates, instead of requiring us to create a separate class just to hold the anonymous method. It also supports automatic type detection, which is another plus. But this is probably a good subject for a future post.
Similar Posts:
About the Author
Carlos Oliveira holds a PhD in Systems Engineering and Optimization from University of Florida. He works as a software engineer, with more than 10 years of experience in developing high performance, commercial and scientific applications in C++, Java, and Objective-C. His most Recent Book is Practical C++ Financial Programming.