David M. Lloyd

Software Engineer at Red Hat, Inc.

View My GitHub Profile

30 September 2008

Dave's Dumb Closures

by

Or: How to add closures to Java without mutilating the language

Those of you know have spoken with me via any media for more than about 45 seconds consecutively know that I am vehemently opposed to the various closure implementations for Java that have been proposed for inclusion in to Java 7. I’m not opposed to closures, mind you - I just really dislike the implementation options that are currently on the table. At one point I had visualized writing The Final Blog Post On The Subject, which would be so sharp of wit that any possible counterargument simply could not stand in the face of it. It would be eloquent, noble, and completely irrefutable - even the staunchest BGGA supporter would be won over.

Then reality sets in, and one is reminded that pretty much every such argument against the different closure ideas has been made, and promptly deflected. So rather than add to that particular category of noise, I thought I’d present a rough outline of a closure implementation that would sit much better with me, in the hopes that there are folks out there who have the same misgivings as I do about the current state of things.

What is a Closure?

A closure is defined in FOLDOCas “a data structure that holds an expression and an environment of variable bindings in which that expression is to be evaluated.”

Basically this translates to Java as two things: A lexically-scoped block of code, and a means to execute that code or pass it on to another method for delayed execution.

The use cases for these things are numerous. Other imperative languages have used them for such things as customized control flow structures, continuations, resource management, and so on. Here in Javaland though, we are left out in the cold - the closest thing we get to these fun toys are anonymous inner classes. And while anonymous inner classes give the impression of being a sort of limited closure (with the caveat that it can only access local variables that were declared final - they’re actually copied to fields transparently), they’re obviously not the real deal.

The current leader, BGGA, takes the approach of taking the anonymous inner class notion a few steps farther - local variables aren’t just copied to fields, they become fields (and thus read/write) - along with lots of language glue (magic dynamically-generated types, lots of new syntax and rules, some special annotations) to make it all work sanely. I’m not going to go into an exhaustive list of What’s Wrong With BGGA; rather I’m going to demonstrate a completely different notion of a closure in Java from what you’ve seen in BGGA and the other competing specs.

A Closure is a Procedure

My view of a closure in Java is simply an inner method - or more accurately, an inner procedure. This differs from BGGA (and anonymous inner classes) in a few ways:

Since many people are visual in nature, allow me to demonstrate a possible syntax and usage for these things.

This first example would be a typical ARM (automatic resource management) scenario. Imagine a Lock interface with a method like this:

    public interface Lock {  
        void hold() for theBlock();  
    }

Notice the use of the “for” keyword. Yeah, I stole that idea from BGGA. Anyway, here’s how you’d implement it:

    public class MyLock implements Lock {  
        // ...stuff...  
        public void hold() for theBlock() {  
            ...acquire the lock using ninja CAS techniques...  
            try {  
                theBlock();  
            } finally {  
                ...release the lock unconditionally...  
            }  
        }  
    }

Finally you’d use it like this:

    private final Lock lock = new MyLock();  
    public void doStuff() throws TheException {  
        // we need to access the shared resource!  
        lock.hold() for() {  
            // ok, let's do some test  
            if (someConditionIsWrong) {  
                throw new TheException("Failure...");  
            }  
        }

Or we could ditch the “for” on usage if there’s no parameters:

    lock.hold() {  
        // do stuff  
    }

Niiiiice.

Now think about this for a moment. Not only does it look awesome, but we’ve removed the virtual method invocations you’d get with BGGA thereby making this potentially super-fast, eliminated an entire category of new magi-types from the language, and solved the Big Exception Conundrum.

Did I go too fast? Let me back up and cover those points.

First - it looks awesome, you can’t deny it. No goofy arrows pointing from nothing to whatever, no weird ({()}) crap, etc. It reads easily in declaration, definition, and invocation, and it’s not a lot of typing.

Next - consider what this closure structure does for performance. With one single method invocation, we are locking the resource, executing the user block, and unlocking the resource. You can’t even beat that using try/finally today - at best you’ve got a method call to lock and a method call to unlock, with your code in between (I’ll get into the mechanics of how the call to the block actually occurs down below, for you skeptics out there).

I won’t cover the magical auto-created interface types in BGGA - if you know what I’m talking about, well, then you know what I’m talking about. If not - you don’t want to know, believe me.

Finally, the Big Exception Conundrum. Due to the fact that the closure is really and truly lexically scoped - not fakey-lexical-scoping like anonymous inner classes and their big BGGA brother - all kinds of tricky issues about exception propagation simply disappear. The complete relevant part of the call stack is statically known at compile-time! Therefore there’s no need to put in special plumbing for the closure to have some fancy dynamic throws list, or for the method which invokes the closure to have any knowledge or regard for what the closure may throw. It will throw whatever the closure’s parent method can catch or propagate at the point that the closure is defined, just like a regular code block. And nonlocal returns can be trivially implemented using the same techniques.

Some More Lovely Examples

The oft-wished-for Map pairs iteration - interface:

    interface Map<K, V> {  
        // ...  
        void iterate() for block(K key, V value);  
        // ...  
    }

Implementation:

    public class FooMap<K, V> implements Map<K, V> {  
        // ...  
        // cheapo implementation just uses good old entrySet()  
        public void iterate() for block(K key, V value) {  
            Set<Entry<K, V>> entrySet = entrySet();  
            for (Entry<K, V> e : entrySet) {  
                block(e.getKey(), e.getValue());  
            }  
        }  
        // ...  
    }

Usage:

    Map<String, Thing> things = new FooMap<String, Thing>();  
    // ...later...  
    things.iterate() for (String key, Thing value) {  
        System.out.println("The string " + key + " is for the thing " + value);  
    }

Think how difficult it was for the BGGA crowd to get control structures in there! And they’re still pretty ugly if you ask me (at least in v0.5 of the draft):

    // weird BGGA stuff...  
    <R, T extends java.io.Closeable, throws E>  
    R with(T t, {T=>R throws E} block) throws E {  
        try {  
            return block.invoke(t);  
        } finally {  
            try { t.close(); } catch (IOException ex) {}  
        }  
    }

This same safe-close control structure would be done like this (notice how absolutely no type parameters are needed):

    public static void with(Closeable resource) for block() {  
        try {  
            block();  
        } finally {  
            try {  
                resource.close();  
            } catch (Throwable t) {  
                // log it, of course!  
            }  
        }  
    }

Then the usage would be:

    InputStream is;  
    with (is = new InputStream("foo.txt")) {  
        // read me my bytes!  
    }

Or how about slick user transaction management (usage only shown):

    txn.begin() {  
        // do some JDBC or Hibernate or something!  
    }  
    // or keep a threadlocal with the context and you could do:  
    transaction() {  
        // do some JDBC or Hibernate or something!  
    }

Or a nice way to handle streaming result sets from a file or database (usage only shown):

    data.fetch() for (String lastName, String firstName, BigDecimal balance) {  
        // Take a hike, data objects.  These are all local variables!  Talk about cheap GC!  
        System.out.println(lastName + ", " + firstName + " owes us $" + balance);  
    }

Privileged actions get a performance boost (no object creation, no virtual method dispatch) - and say goodbye and good riddance to PrivilegedExceptionAction:

    AccessController.doPrivileged() {  
        secretStuff.activate();  
    }

Nuts & Bolts

The way I describe these closures is based on a few key technical ideas.

Other Ideas Based On Real Closures

tags: