Summary
There are at least 4 inner class/closure proposals for Java 7 and it is hard to compare them because they use different terms and different syntax for similar concepts. This post makes the comparison easier by seperating concerns.

Advertisement

Comparing Inner Class/Closure Proposals

There are at least 4 inner class/closure proposals for
Java 7 and it is hard to compare them because they use different terms and
different syntax for similar concepts.
The idea of this post is to separate out the inner class/closure part of
the proposals from the extras and make explicit that the extras can
be added or taken away from any of the proposals or be part of other proposals;
because they are separate concerns.
This separation of concerns gives clarity and also allows you to roughly
rank the various features (my ranking is the order presented).

In some instances
there is synergy between these separate concerns and hence these extras are
presented together with the main proposal. In fact all but the
CICE
proposal covers issues other
than the inner classes/closures themselves. Before continuing I should declare
my self-interest; I authored the
C3S proposal.
Explanations and examples of the
different features are given below, but first an “at a glance” comparison.

1. Short syntax for the creation of an instance of an inner class/closure

Y

Y

Y

Y

2. Access to both this pointers and methods within an inner class

Y

Y

3. More than one method in an inner class/closure instance

Y

4. Implementation of methods defined in classes

Y

Y

5. Type inference

Y

Y

Y

Y

6. Method, constructor, and field literals

Y

7. Short syntax (particularly for control structures and short methods)

Y

Y

Y

8. Assignment to local variables and no final requirement

Y

Y

Y

Y

9. Variable number of exceptions

Y

Y

Y

Y

10. Method/function types (with shorter syntax)

Y

Y

11. Non-local, return, break, and continue

Y

Y

Y

Definition of terms

Closure is a new term in the current Java 6 context; closures are like inner
classes except that the normal inner class this pointer isn't available,
only the pointer to the enclosing class, which is confusingly (?), called
this.

BGGA
is Closures for the Java Programming Language v0.5 (named after the initials
of the authors)

Summary of features

From the table you can see that the proposals only really agree that there
should be: short syntax for inner classes/closures, more type inference,
a variable number of exceptions,
and that the read-only and final declaration restriction for
local variables should be removed. Should these be the only extensions made
to Java?

As for the other features, that depends upon the weighting
you give each feature. This weighting need not be a simple progression
of a weighting of 11 for your number 1 to a weighting of 1 for your number
11. For example I personally give little weighting to my numbers 8 to 11
inclusive; however others find these points important and therefore I have
included some of them in my C3S proposal to hopefully broaden acceptance.

Explanations and examples

1. Short syntax for creation of an instance of an inner class/closure

This is the focus of all the proposals and a typical use
is to apply a method to the elements in a collection.

BGGA

2. Access to both this pointers and to methods within an inner class

This is the real distinguishing feature between a closure
and an inner class, a closure only has access to the this
pointer associated with the enclosing
class and not, also, its inherited this pointer.
Therefore inside a closure you cannot call any other method of the closure including
itself (inner classes don’t have these restrictions). C3S and CICE have inner
classes, whereas FCM and BGGA only have closures. Anything that can be done
with a closure can therefore be done with an inner class but not vice
versa. For inner classes there may be a case for adding a keyword, say
enclosing, that is used like this,
but refers to the enclosing class
(what do people think about adding this keyword?). For me this is a very
important feature, so I will give three examples.

A. Reducer

Firstly, consider a
reduce method (a.k.a. fold) on a list. If you had a class
Reducer as shown, using Java 6 syntax:

CICE (Constructor must have zero arguments, therefore
use straight Java 6 code. Alternatively code similar to FCM above could
be used.)

BGGA (Only one this, therefore make total explicit
and use each instead of reduce.
Code not shown since it is similar to FCM above.)

B. Recursion

The second example of needing access to the methods inside
the inner class is recursion (without access to methods within the inner
class you cannot use recursion — it is a long while since I used a language
without recursion :-( ). Given a list of Integers:

CICE (Constructor must have zero arguments and only
one method allowed, therefore use straight Java 6 code as above.)

BGGA (No access to methods within the closure from
within the closure, therefore use Java 6 as shown for FCM above.)

C. Worker

With the advent of multi-core processors the importance of multi-threaded
code will increase. Any new language features should anticipate this trend
and a favour multi-threading. Access to the enclosing scope is of less value
in a multi-threaded environment since the enclosing scope may be long gone
when the method is evaluated. Multi-threading therefore emphasizes access
to the inherited this pointer and to methods and fields within
an inner class.

For example, at times you need to wait for previous tasks to complete before
proceeding. This can be done by waiting for Futures to complete;
a Future's get method will sleep a thread for example.
Unfortunately a Thread is expensive and therefore you ideally
don't want to sleep one. Instead you might delay scheduling a calculation until
its inputs are ready:

FCM and BGGA cannot implement submitWithGuard, as
shown above, because it accesses the inherited this and instead normal Java
6 would be used or a name would be given to the inner class via a method declaration
(which would then be wrapped in a Runnable). A CICE implementation
would be similar to the above code, but a little more verbose.

3. More than one method in an inner class/closure

C3S is unique in allowing the overriding of more than one
method. The others can only override one method and therefore some uses,
particularly for asynchronous calls, can’t be accomplished directly. EG imagine
a method called time that
takes an array of Callable methods,
runs them all a few times and in different orders, and then reports the average
execution time for each as well as checking each call gives the same result.
This time method requires
objects that have a call method
from Callable, but also uses
the toString method for identification
and reporting purposes.

4. Implementation of methods from classes

No problem with C3S and no problem for CICE provided that
for CICE there is only one abstract method to override (see point 3 above).
FCM can implement a method from a class provided that only one method is
to be implemented, the class doesn't have generic arguments, the class
has a no-arg constructor, and no access is required to other class members.
BGGA can’t use classes
at all. Consider an Integer array
factory (a factory that returns a List of Integers,
but the list is fixed sized):

5. Type inference

C3S, FCM, and BGGA have some type inference and CICE states
that type inference could be added. The type inference for C3S
(but see below for other examples),
FCM, BGGA, and suggested for CICE is to infer a class/interface/method name.
EG the sort example given in 1 above which in C3S is:

sort ls, method( s1, s2 ) { s1.length - s2.length };

Infers: the interface name, Comparable,
the generic type parameter, String,
the return type, int, the
method argument types, both String,
and the method name, compare.
The examples for BGGA and FCM are almost identical, except that the argument
type is needed, and therefore FCM and BGGA are not shown; for CICE you need
to supply the interface name and argument types (see 1 above). The type inference
in C3S is however much more extensive than for the other proposals and more
extensive than the above example demonstrates. The C3S type inference is
similar in scope and nature to the type inference that is in Scala. This
copying of Scala is an important point, since Scala demonstrates that this
level of type inference is practical and still produces good error messages
unlike more extensive type inference in other languages. In C3S the method
construct given above can be used for any declaration,
e.g. an anonymous AbstractList:

Also in the AbstractList example above note how
the type of variable declarations are inferred from the right hand side.
To support this type inference a new keyword declare is
added for non final declarations, e.g.:

declare list = ArrayList.new( 1, 2, 3 );

Instead of:

List< Integer > list = new ArrayList< Integer >( 1, 2, 3 );

6. Method, constructor, and field literals

The FCM proposal provides syntax for method, constructor,
and field literals (currently only a type has a literal in Java,
name.class, and strings have to be used
for the others). The proposal in FCM mimics the construct used in Javadocs,
e.g.:

7. Short syntax (particularly for control structures and short methods)

C3S, FCM, and BGGA provide short syntax for constructs
other than inner classes/closures, the other proposals don’t address further
short syntax. First BGGA, it has two other short syntax constructs
one for short methods and one for control like constructs. The short method
construct is from within a closure only (i.e. not generally available).
The short method construct is that return isn’t used; instead
a statement without a terminating semicolon must be used instead.
E.G.:

BGGA also provides short syntax for control structures,
it uses the for keyword to
identify these methods and allows the movement of the closure to outside
the method brackets, provided that the closure is the last argument. E.G.
an each iterator might be:

FCM does not have any short method syntax but it does have control syntax,
much along the lines of BGGA and therefore not shown.

C3S takes a different
approach than BGGA, it provides general short constructs, not just specifically
for inner classes, that can be used throughout Java and all of which are
optional. Type inference, discussed above, is an example. Others examples
are: method declarations in general, generic declarations, inference of generic
types for constructors, declaration of constructors, and declaration of properties.
See C3S for
details. It is interesting to note that in the vast majority of examples
C3S versions are the most concise; this is a surprising result since C3S’s
design favoured clarity and therefore used keywords rather than symbols and
since the keywords are longer than the symbols used in other proposals you
might expect C3S to be verbose. The reason that C3S is the most concise, is
because generally applicable constructs have been favoured in C3S over constructs
with a few use cases.

For all methods C3S makes return optional
and uses the value of the last line in the block if return is
omitted, therefore the invert example
above in C3S would be:

For all methods C3S makes unambiguous brackets optional
(like Ruby) and makes the semicolon before a closing brace optional (like
Pascal), therefore the for example in C3S is:

each ls, method( e ) { total += e };

8. Assignment to local variables and no final requirement

All the proposals are basically the same, they allow writing
to local variable (in the case of CICE a writable local needs to be annotated
with public) and there is no need to declare local variables final.
Since all the proposals are so similar on this point only C3S is shown:

In BGGA you can turn off access to non-final local variables by making
the interface that the closure implements the method of extend
RestrictedFunction. It is not clear how practical this
technique of adding RestrictedFunction would be since
you can't retrofit to existing code easily.

9. Variable number of exceptions

At times it is convenient to be able to declare very general
methods that throw any number of exceptions, including checked exceptions.
Currently either RuntimExceptions only are
allowed, e.g. Runnable, or Exception,
as opposed to a specific exception list, is thrown, e.g. Callable.
C3S, FCM, and BGGA propose solutions, C3S uses generic varargs and FCM and
BGGA provide a similar capability but don’t use the varargs syntax.

C3S

FCM & BGGA

interface Method1< R, A1, throws Es > {
R call( A1 a1 ) throws Es;
}

CICE

Joshua Bloch (one of the authors of CICE) said in an email:

While CICE [JB said BGGA but I am sure he meant CICE] doesn't specifically allow for disjunctively typed throws clauses (“Variable number of exceptions”) it doesn't rule it out either. I see this as a defect in the generic typing facility that should be fixed there. Once so fixed, it will apply to all parameterized types, even those produce using old-fashioned anonymous class instance creation expressions.

This is a fair point, “Variable number of exceptions” is a seperate concern.

10. Method/function types (with shorter syntax)

FCM and BGGA both provide support for declaring the type
of classes that contain a single method. In both cases the syntax is based
on their inner class/closure syntax, e.g.:

In both cases the types above are translated into a standard interface, e.g.:

Method1< Void, MouseEvent >

See point 9 above for the definition of Method1. To
convert the anonymous method given in the above example to an instance of
Method1 the correct generic parameters for Method1 need to be inferred. The
generic arguments are easy, since they are explicitly stated, the return
type of the anonymous method is however potentially difficult. Consider (in
FCM syntax):

With C3S (and potentially with CICE, but the concept isn’t
explicitly mentioned) there is no new syntax and instead Method1 is
used directly. This option avoids the difficulty of inferring the return
type. The equivalent “mouse” line in C3S and CICE is:

Note how the generic arguments to Method2 when declaring add use
variance. The idea is to increase the generality of the method, this is
a laudable aim.

11. Non-local return, break, and continue

C3S, FCM, and BGGA support non-local return, break,
and continue, whereas CICE doesn’t. In BGGA this facility is highly
emphasized whereas in C3S it is listed as a possible future option. In BGGA
it is considered a most
important feature and new syntax is introduced into closures for normal method
return and the normal method return syntax is used for a non-local
return (see point 7 above). It is hard to find a good usage example for non-local
returns because throwing an exception is a viable alternative; in fact they
are implemented by throwing an exception! Another point to note is that the
concept of non-local returns is only applicable in single threaded code in
which the evaluation order is well known (typically sequential). This style
of coding will be used less in the future because processors are all going
multi-core and therefore favour multi-threading. (This multi-core and hence
multi-threading for the future was noted in point 2 above.)

As already noted; a good example
is hard to find, but suppose that the collections library did not contain
binarySearch but did contain each
(and you didn’t want to use a loop!):

BGGA

(The most common justification for the non-local return
feature of BGGA using the traditional method return syntax is that it allows
easy refactoring of something like a for loop into an
each loop. It is true that this refactoring
is simple in BGGA, but I would suggest that the more common refactoring
of an inner class’s method/closure into a stand-alone method is now harder.
Therefore the use of normal method syntax for non-local return seems dubious.
The value you place on this feature would seem to depend on your programming
style. If you use a heavy procedural style then you might make extensive
use of blocks nested inside one another. However if you use an OO style or
a functional style you are much more likely to use a lot of small methods
instead and therefore hardly ever use a non-local return.)

In BGGA you can turn off non-local returns by making
the interface that the closure implements the method of extend
RestrictedFunction. It is not clear how practical this
technique of adding RestrictedFunction would be since
you can't retrofit to existing code easily.

Code for FCM would be similar to the above BGGA code and therefore isn't shown.
There is however a major point of difference between FCM and BGGA, in BGGA a
non-local return is allowed for all closures. In FCM non-local
returns are only allowed in control blocks.
In fact in FCM all return statements within a control block are non-local
returns and further more the return type of a control loop block is void
and therefore no confusion exists as to whether a return is local or not.
This difference concerning non-local returns considerably simplifies the FCM proposal.

Acknowledgements

Stefan Schultz and Stephen Colebourne (the authors of
FCM) both suggested that I write this blog. I asked the authors of the
respected proposal to check my examples of their code, thanks
to those who responded.

Nice job comparing the proposals. That said, I would prefer that Java not have closures at all and if it was to get them, I would prefer it to use the syntax that Groovy uses for closures.

Again, Java should not have closures. Java was designed with certain principles in mind (like same syntax as C/C++, etc.) and the more you stray from those principles, the more you just pollute the language into a monstrosity. If you want next-gen language constructs, use a next-gen language (like Groovy or Ruby). Personally, I would prefer Groovy to simply replace Java over time.

Good Job Howard, C3S looks very clean. Although I really like BGGA control invocation syntax, your expression looks cleaner over all.

I hope that when EG is formed, your participation will help ensure that Java remains a competitive language in the future such that our existing investment can be grown without reservation. (JCP should really expedite its community voting mechanism)

Aside from minor inconveniences, inner classes already provide much of the functionality of closures, therefore syntax should be be concise, clean and familiar as it would represent what appears to be the biggest improvement to the current means of abstraction at the method level.

Thanks for your comments. I agree with everything you said (including liking the control loop invocation syntax in BGGA, I have my reservations about the declaration syntax and about just how useful new control loops are). It would be good if some sort of consensus could be reached via the JCP.

I think the Ruby-like invocation syntax of C3S obscures the comparison a little. This omission of parens seems orthogonal to the closure-related modifications; for the purposes of comparing closure proposals, it would be more useful to see the C3S examples with the extra parens. Alternatively, you could try writing out all the proposals without the extra parens.

(BTW, I think removing the parens from Java is too radical a change. If you're willing to go that far, you might as well use Scala!)

I am hoping that one of the values of this comparison is to enable people to prioritize which of the separate concerns they like and which option for a given concern they like. So taking your example, you don't like option 7 Short Syntax or at least not the C3S options for short syntax. That is useful feedback on the proposals.

As an aside, the reason that I preferred making () optional over special syntax for a given control structure is that it achieves a similar level of conciseness and yet has many more uses cases. Personally I find all the () in Java cluttering and don't think they add to clarity much.

But as I said the purpose of the blog is to separate concerns and let people have their say.

> I am hoping that one of the values of this comparison is> to enable people to prioritize which of the separate> concerns they like and which option for a given concern> they like. So taking your example, you don't like option 7> Short Syntax or at least not the C3S options for short> syntax. That is useful feedback on the proposals.

Actually, I was trying to say that your examples don't fully separate concerns. Most of the C3S examples (not just the ones in section 7) omit parentheses on method invocations.

Omitting parentheses on method invocations is a feature that is mostly orthogonal to the core closure-related issues (it could probably be added on to any of the other proposals). Therefore, I think it's best to keep that feature out of sight. The easiest way to do that is to change the C3S examples on this page to use parentheses on method invocations (except perhaps in the few cases where it is relevant).

> Personally I find all the () in Java cluttering and don't> think they add to clarity much.

I agree and that's one of the things I like about Ruby (and Scala). It's just that without them, it doesn't even look like Java code anymore :)

> Actually, I was trying to say that your examples don't> fully separate concerns. Most of the C3S examples (not> just the ones in section 7) omit parentheses on method> invocations.

Sorry for not getting your point first time. I did consider using standard Java except for the feature under discussion. For example, not using short syntax for inner classes/closures, point 1, except when discussing point 1. This would effect the presentation of all the proposals, not just C3S. In the end I decided it was best to show all examples, in each syntax, in what I considered the most likely way that example would be written in a particular syntax.

> Omitting parentheses on method invocations is a feature> that is mostly orthogonal to the core closure-related> issues (it could probably be added on to any of the other> proposals).

Yep I agree, it almost certainly a feature that could be added to the other proposals. It is a two way street though, for example the BGGA control loop syntax could be added to C3S. However I was documenting the proposals as they stand. Maybe you want to choose the variations you like and give some examples in another set of features.

> > Personally I find all the () in Java cluttering and> don't> > think they add to clarity much.> > I agree and that's one of the things I like about Ruby> (and Scala). It's just that without them, it doesn't even> look like Java code anymore :)

I didn't particularly push the no () point. One of the advantages in eliminating () is that it lets you make an embedded-domain-specific language more easily. Because you can make a library call look like a statement. Many of the Ruby libraries use this to great effect.