Understanding the closures debate

Does Java need closures? Three proposals compared

1 2 3 4 5 Page 2
Page 2 of 5

Closures: Three proposals compared

While the three closures proposals agree in their desire to bring the expressive power of closures to the Java syntax, they disagree about the manner of doing it. For one thing, the proposals differ -- sometimes greatly -- in how much additional power they would bring to the Java language. They also differ in terms of how closures are to be integrated into the existing language. One of the chief arguments against adding closures to the language is, of course, complexity. We'll look at how each of the proposals addresses this issue below, following a brief overview of each one's origin and basic intent.

Counting by numbers
To get a feeling for the attention this topic attracts, consider the following figures: with three proposals for closures in Java(not counting what some call the fourth proposal: no closures at all) Alex Miller's Closures in Java 7 Web page lists nearly 150 articles, blog posts, or other resources related to this topic. No other feature in Miller's coverage of proposed additions to Java 7 has received so much attention; most features have 10 entries at best. Even the runner-up, the fairly controversial Java Module System, has just 60 entries to date.

BGGA

Issued in August 2006 the BGGA proposal started the "closures in Java" discussion. The acronym BGGA comes from the first letters of the last names of its four authors: Gilad Bracha, Neal Gafter, James Gosling, and Peter von der Ahé. Of that group, Neal Gafter has been the most vocal advocate for BGGA, which is undeniably the most ambitious of the three proposals. BGGA adds a lot of power to the Java language, but also a lot of complexity.

CICE plus ARM

CICE stands for "Concise Instance Creation Expression." Developed by Bob Lee, Doug Lea, and Joshua Bloch, CICE has been strongly championed by Bloch. The CICE proposal is considerably less complex than BGGA and advocates an approach that is best described by its tagline: closures without complexity. In CICE, closures are essentially an alternative syntax for inner classes. CICE closures stick close to the existing Java language and do not add much new functionality.

One use case has especially shown the limits of CICE, and that is "resource management with finally," where BGGA outperforms CICE with its functional power. To compensate for this shortcoming Joshua Bloch has proposed an object-oriented resource management approach (an addition to the existing, more functional approach with finally). He calls this proposal ARM (Automatic Resource Management). When most people talk about CICE today, ARM is implicitly included. Mark Mahieu has developed a prototype implementation for CICE plus ARM.

FCM plus JCA

FCM, which stands for First Class Methods is the closures proposal developed by Stephen Colebourne and Stefan Schulz. With respect to power and complexity this approach is somewhere between CICE and BGGA, and is much closer to BGGA. It mainly differs from the other two proposals in how it introduces closures into the Java language: not as an isolated novel concept, but embedded into an approach that allows handling of types and references of methods as first-class elements in Java. In FCM, a closure is just a special kind of method: the inner method.

BGGA also outperforms FCM by allowing for the implementation of custom control abstractions, which are static helper methods that receive a closure as a parameter. A separate proposal for Java control abstractions (JCA) addresses the need for custom control abstractions in FCM.

Next, we consider the specific benefits of closures and see how they're handled by the three proposals.

The closures proposals in practice

One common goal of all the closures proposals is to simplify the process of passing a piece of functionality to a method. Let us see how the various proposals would achieve this goal.

CICE (Concise Instance Creation Expression)

CICE only introduces minor changes to the way that we currently pass functionality to methods in Java programs. We still need the Block interface, which we use as the type of the functionality when we declare the forEach method. Hence, the forEach method does not change at all. The invocation syntax is more concise and convenient, however, as shown in Listing 2.

Listing 2. Declaration and invocation of method forEach using CICE

public interface Block<T> {
      void invoke(T arg);
    }
    public class Utils {
      public static <T> void forEach(Iterable<T> seq, Block<T> fct) {
        for (T elm : seq)
        fct.invoke(elm);
      }
    }
    public class Test {
      public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1,2,3);
        Block<Integer> print
          = Block<Integer>(Integer arg) { System.out.println(arg); };
        Utils.forEach(nums,print);
      }
    }

Instead of creating an anonymous class of type Block<Integer> we create a closure. In CICE the closure is called a concise instance creation expression, hence the name of the proposal. Essentially, the proposal boils down to a more convenient syntax, because we can replace the syntax for creating an anonymous class with the more concise syntax of the closure. The closure syntax is available for all interfaces with exactly one method, such as Runnable, Callable, or ActionListener. CICE meets the goal of simplifying the use of these interfaces.

BGGA

This proposal introduces a new kind of type so far unknown in Java, namely a function type. A function type denotes the type of a closure. With the function type, we no longer need the Block interface in our example. Instead we use the function type {T => void}, which denotes a function with an argument of type T that returns void.

We use this function type when we declare the forEach method's second argument, as shown in Listing 3.

Listing 3. Declaration of method forEach with BGGA's function type

class Utils {
      public static <T> void forEach(Iterable<T> seq, {T => void} fct) {
        for (T elm : seq)
        fct.invoke(elm);
      }
    }

All closures implicitly have an invoke method so that we need not change anything else in the forEach method. Basically, you can assume that the compiler translates the function type to a synthetic interface type that looks like our Block interface.

We use another quite similar function type, {Integer => void}, when we create the actual closure that we pass to the call of the forEach method, as shown in Listing 4.

Listing 4. Invoking forEach using a BGGA closure

class Test {
      public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1,2,3);
        {Integer => void } print
           = { Integer arg => System.out.println(arg); };
        Utils.forEaxh(nums,print);
      }
    }


The variable print is a function reference of a function type and refers to a closure. It is initialized with a closure that in our example takes an Integer and prints it. The closure is then passed to the forEach method and applied to each element in the sequence.

FCM

The First Class Methods proposal goes one step further and does not only add function types (here called method types) that denote the type of a closure, but the type of a method in general. Closures in this proposal are just a special case of a method, namely an anonymous inner method, which is method without a name. Naturally, the syntax is different; our method type looks like #(void(T)) in this proposal and the closure is denoted as #(Integer arg) { System.out.println(arg); }:

Listing 5. Declaration and invocation of method forEach using FCM

class Utils {
      public static <T> void forEach(Iterable<T> seq, #(void(T)) fct) {
        for (T elm : seq)
        fct.invoke(elm);
      }
    }
    class Test {
      public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(1,2,3);
        #(void(Integer)) print
          = #(Integer arg) { System.out.println(arg); };
        Utils.forEach(nums,print);
      }
    }


As you can tell from the examples, the proposals use different syntax to achieve their goal, in this case passing functionality to a method, but the underlying idea is similar. Next we'll look at how each proposal approaches closure conversion and type compatibility.

1 2 3 4 5 Page 2
Page 2 of 5