Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closures in Java - syntax differences between the three major proposals?

Three major proposals for adding closures to the Java language has been presented:

  • BGGA (Bracha Gafter Gosling Ahé) also known as "full closures", by Gilad Bracha, Neal Gafter, James Gosling and Peter von der Ahé
  • CICE (Concise Instance Creation Expressions) also known as "simplified inner classes", by Bob Lee, Doug Lea and Josh Bloch
  • FCM (First Class Methods), by Stephen Colebourne and Stefan Schulz

My question:

  • What are the differences between the three proposals (BGGA, CICE and FCM) in terms of syntax?
like image 861
knorv Avatar asked Nov 25 '09 18:11

knorv


1 Answers

This IBM paper gives good examples of the syntax difference between BGGA and CICE:

The BGGA proposal

The BGGA proposal creates a concept of function types, where a function has a typed argument list, a return type, and a throws clause. In the BGGA proposal, the sum-of-squares code would look like the code in Listing 9:

Listing 9. Calculating the sum of squares using the BGGA closure syntax

sumOfSquares = mapReduce(myBigCollection, 
                         { Double x => x * x }, 
                         { Double x, Double y => x + y });

The code inside the braces to the left of the => symbol identifies the names and types of the arguments; the code to the right represents the implementation of the anonymous function being defined. This code can refer to local variables defined within the block, arguments to the closure, or variables from the scope in which the closure is created.

In the BGGA proposal, you can declare variables, method arguments, and method return values that are function types. You can supply a closure in any context where an instance of a single abstract method class (like Runnable or Callable) is expected; for anonymously typed closures, an invoke() method is provided so you can call them with a specified argument list.

One of the primary goals of the BGGA proposal is to allow programmers to create methods that act like control structures. Accordingly, BGGA also proposes some syntactic sugar to allow you to call methods that accept closures as if they were new keywords so that you can create methods like withLock() or forEach() and invoke them as if they were control primitives. Listing 10 shows how the withLock() method would be defined under the BGGA proposal; Listing 11 and Listing 12 show how it would be invoked, using both the standard form and the "control construct" form:

Listing 10. Coding the withLock() method under the BGGA closures proposal

public static <T,throws E extends Exception>
T withLock(Lock lock, {=>T throws E} block) throws E {
    lock.lock();
    try {
        return block.invoke();
    } finally {
        lock.unlock();
    }
}

The withLock() method in Listing 10 accepts a lock and a closure. The return type and throws clause of the closure are generic arguments; type inference in the compiler generally allows it to be invoked without specifying the value of T and E, as in Listing 11 and Listing 12:

Listing 11. Invoking withLock()

withLock(lock, {=>
    System.out.println("hello");
});

Listing 12. Invoking withLock() using the control construct shorthand

withLock(lock) {
    System.out.println("hello");
}

Like generics, much of the complexity of closures under the BGGA proposal is borne by library creators; using library methods that accept closures is much simpler.

The BGGA proposal also works to repair a number of transparency failures that are present when trying to use inner class instances to gain the benefits of closures. For example, the semantics of return, break, and this are different in a block of code than they are in a Runnable (or other inner class instance) that represents the same block of code. These elements of nontransparency can cause confusion when migrating code to take advantage of generic algorithms.

The CICE proposal

The CICE proposal is a simpler proposal that addresses the problem that instantiating inner class instances is too cumbersome. Rather than create a notion of function types, it simply creates a more compact syntax for instantiating instances of inner class with a single abstract method (such as Runnable, Callable, or Comparator).

Listing 13 shows what the sum of squares code would look like under CICE. It makes explicit the UnaryFunction and BinaryFunction types used by mapReduce(). The arguments to mapReduce() are anonymous classes derived from UnaryFunction and BinaryFunction; the syntax simply elides much of the redundancy associated with creating an anonymous instance.

Listing 13. Sum of squares code under the CICE closures proposal

Double sumOfSquares = mapReduce(myBigCollection,
    UnaryFunction<Double>(Double x) { return x*x; },
    BinaryFunction<Double, Double>(Double x, Double y) { return x+y; });

Because the objects representing the functions passed to mapReduce() are ordinary anonymous class instances, their bodies can refer to variables defined in the enclosing scope; the only difference between the approaches in Listing 13 and Listing 7 is the verbosity of the syntax.

like image 52
JRL Avatar answered Oct 15 '22 06:10

JRL