Skip to main content

Dr. Gafter comes to SJSU

Posted by cayhorstmann on April 12, 2007 at 10:30 PM PDT

I teach a graduate programming languages class at San Jose State
University. In order to inject some topics of current interest, I had a
lab about closures and the competing closure proposals for Java 7. I got
an email from Neal Gafter: “Hey, it's really cool to see your
reference to BGGA in a SJSU lab assignment!” I asked if he could
give a talk at the department seminar, to which he graciously agreed. We
had a packed room today. I am very excited that my students had a chance
to witness a bit of history in the making. Here are my impressions of the

The End of History - Not.

I have taught href="">CS252
for many years. I cover the lambda calculus, closures, continuations,
metaprogramming, and other advanced programming language topics. For
several years, my graduate students viewed the material as having little
relevance to their lives. Clearly, real programming languages had evolved
from C to C++ to Java, and href="">the end of
history had been reached. Every other language was either some poorly
designed pile of crud or an ivory tower obsession.

I tried what I could, talking about href="">continuations
for web applications and Paul Graham's article on href="">Lisp in a startup. My
students, however, are by and large a pragmatic bunch. They know that web
applications aren't written in Lisp, and googling for Paul Graham led them
to this href="">funny
but unflattering article.

This year, things were finally going my way. The buzz behind Ruby and
Rails is hard to ignore, and it seems pretty clear that Java will get
closures in some form or other. Learning about metaprogramming and
closures doesn't seem a waste of time any more.

How Not to Write a Proposal

Alex Miller has a nice blog on Java 7 proposals, including the href="">competing closure
proposals. My students found the href="">CICE proposal
pretty straightforward. It starts out with a simple promise:

For example,
here is the Java 5 code to start a thread whose run method invokes a
method named foo:

    new Thread(new Runnable() {
        public void run() {

If we adopt this proposal, the following code would be

new Thread(Runnable(){ foo(); }).start();

The first impression is that this is easy and convenient.

In contrast, the BGGA
starts out with:

programming languages provide a mixture of primitives for composing
programs. Most notably Scheme, Smaltalk, Ruby, and Scala have direct
language support for parameterized delayed-execution blocks of code,
variously called lambda, anonymous functions, or closures. These provide a
natural way to express some kinds of abstractions that are currently quite
awkward to express in Java. For programming in the small, anonymous
functions allow one to abstract an algorithm over a piece of code; that
is, they allow one to more easily extract the common parts of two
almost-identical pieces of code. For programming in the large, anonymous
functions support APIs that express an algorithm abstracted over some
computational aspect of the algorithm. For example, they enable writing
methods that act as library-defined control constructs.

I translated this into plain English in my lecture:

We are smarter
than you are.

The proposal then goes on to discuss closure literals, function types,
closure conversions, exception type parameters, definite assignment, the
type Unreachable and control invocation syntax. That section
finally contains a compelling example:

with(FileReader in : makeReader()) with(FileWriter out : makeWriter()) {
    // code using in and out

No more try/finally/in.close. Hooray!

When we discovered that BGGA gives us this and CICE doesn't, we were
getting much more excited about it.

The Presentation

Neal told me before the talk that he has given this presentation
fifteen times already—someone ought to make a movie about him
tirelessly criss-crossing the planet and spreading the message :-)
Actually, you can see a href="">video
of the presentation here.

He started out with this quote:

"In another thirty years people will laugh at anyone who tries to
invent a language without closures, just as they'll laugh now at anyone
who tries to invent a language without recursion." - Mark Jason

I am not sure whether my students understood this—they had
probably never seen a language without recursion. Sure, I tell them in the
undergraduate programming languages class about Fortran, but they view it
as a freakish thing, like a two-headed cow, not as something that was
taken seriously in its time. But Neal went on to say that one now says the
same thing about garbage collection, and my students do remember the dark
ages of C++ and having to call delete (but not too often).

Neal systematically defined closures, discussed why anonymous instance
creation expressions fell short, defined the requirements for a true
solution, went over syntax, and finally presented the examples. The talk
is much easier to follow than the spec, and everyone enjoyed it

Still, if I had given the talk, I would have given the examples first.
Since this is my blog, I get to do it my way, so here goes.

Closing Locks, Files, Database Connections

Don't you hate writing this code?

Connection conn = dataSource.getConnection();
try {
   . . .
} finally {
   try {
   } catch (SQLException ex) {}

On a bad day, I even worry about a SQLException that triggers
the finally clause, only to have a second exception occur in
conn.close() that masks the first one.

With BGGA closures, you write

with (Connection conn : dataSource.getConnection()) {
   . . .

Iterating over Maps

I can't ever remember whether it is

for (Map<String, Integer>.Entry entry : map.entrySet()) {
   String key = entry.getKey();
   Integer value = entry.getValue();
   . . .


for (Map.Entry<String, Integer> entry : map.entrySet())

I either look it up in Core
or, if I am lazy, I sheepishly fall back on

for (String key : map.keySet())

and feel bad about paying for the additional get.

With BGGA, I can have

for eachEntry(String key, Integer value : map) {
   . . .

I want that.

For that matter, I want to iterate over a two-dimensional array as

for eachIndex(int i, int j : matrix)

without abominations such as a[i].length. I also want to have
both index and value when iterating over a list. With BGGA, I can make
control structures for those purposes.


All the closure proposals handle this use case, but here goes, for the
sake of completeness:

myButton.addActionListener({ ActionEvent event => model.myButtonAction(); });

It seems a shame that one has to do something with the useless
ActionEvent. Ideally, I'd like to be able to ignore the parameter
and write

myButton.addActionListener({ => model.myButtonAction(); });

But maybe it's asking too much.

Logging Exceptions

Neal didn't talk about this, but I gather from the spec that this must
be possible.

I hate writing reflection code like this:

try {
   m.invoke(arg1, arg2);
catch (IllegalAccessException ex) {
   logger.log(Level.SEVERE, "", ex);
} catch (IllegalArgumentException ex) {
   logger.log(Level.SEVERE, "", ex);
} catch (InvocationTargetException ex) {
   logger.log(Level.SEVERE, "", ex);

If I understand the proposal correctly, I can instead write

<throws IllegalAccessException|IllegalArgumentException
      |InvocationTargetException>.tryAndLog(logger) {
   m.invoke(arg1, arg2);

It's still not pretty, but I can't fault BGGA for a cumbersome API with
a method that throws three unrelated exceptions.

Process and Politics

Neal talked a bit about the process of getting a language extension
accepted for the Java language. The JSR process seems rather
company-centric and doesn't seem to deal all that well with the
possibility that two people from the same company (in this case, Neal
Gafter and Josh Bloch, both of Google) have differing views. Still, he
hinted that something will happen in the near future about getting a JSR
on closures started.

Overall, my impression was that Neal's approach is right. You want to
be able to take a block of code, wrap it up and hand it to some other code
and just have it work. Anonymous inner classes won't do it, no matter how
much syntactic sugar you sprinkle over them. When evaluating the competing
proposals, I suggest that you look at the use cases first before you get
flummoxed by the syntax (which may well change) and the arcane
considerations of definite assignment.

Related Topics >>