Inner Classes Are Not Closures

I’ve been absorbing JINI all morning. My brain’s full and as it percolates, I think I’ll post on language design. I’ve been reading Matt writing about language design. This is a subject he actually knows. He has a vocabulary for describing language features and can discuss them in the abstract.

I, on the other hand, am just a programmer who can’t do what I want at times because computers are uncooperative.

For example, I am testing the piece of code that I mentioned previously that loads a large dataset. I know it’s dying at some point and I would like to know the progress.

I started off by printing a message every thousand lines that are processed. That works well with a message every couple seconds until things start to slow down, then it goes to a message every ten minutes. So, I decided I would split the printing out into another thread so I it could print every few seconds regardless of the state of the other object. The code I wrote looked like (with more variables and a try/catch block):

LastFMLoader loader = new LastFMLoader();
Thread logger = new Thread() {
    boolean finished = false;
    public void run() {
        while(!finished) {
            loader.log.info(String.format("%d", loader.lineCount));
            this.sleep(3000);
        } } };
logger.start();
loader.loadFiles(args);
logger.finished = true;

This won’t work for a couple of reasons. The first is java doesn’t have real closures. In a language with real closures, the reference to loader within the inner class would get pointed to the reference to loader in the scope where the class was defined.

Java copies items from the containing scope, so they have to be declared immutable with the final keyword. Not a huge deal for this situation since I don’t want to change the loader. The other problem is more difficult however, I can’t add publicly accessible additions to anonymous classes. This means I can’t expose logger.finished (nor could I define a loader.setFinished()). Also, because fields referenced from the containing scope have to be final, I can’t define finished outside the class.

What I have to do is define an explicit inner subclass in order to expose the field. The final code, which is extremely similar to the original, is:

final LastFMLoader loader = new LastFMLoader();
class LastFMLogger extends Thread {
    boolean finished = false;
    public void run() {
        while(!finished) {
            loader.log.info(String.format("%d", loader.lineCount));
            this.sleep(3000);
        } } };
LastFMLogger logger = new LastFMLogger();
logger.start();
loader.loadFiles(args);
logger.finished = true;

Imagine though if I wanted to kick off a logger for each of ten loaders and I wanted each logger to track multiple variables in the containing scope. The lack of actual closures means all that state has to explicitly copied by me.

I really like the heavyweight structural management of java. It’s arguable that lightweight dynamic structures that closures encourage will lead developers to design extensible generalized code. There’s always a balance between quick one-offs and general toolkits. If you make it really easy to one-offs, the fear is programmers will only write project specific code.

It looks like some of the JSRs for Java 7 are looking at closure-like functionality, so maybe we’ll get to see.


Update: Matt points out that this code should actually be:

final LastFMLoader loader = new LastFMLoader();
TimerTask logger = new TimerTask() {
    public void run() { loader.log.info(String.format("%d", loader.lineCount)); }
};
Timer loggerTimer = new Timer();
loggerTimer.scheduleAtFixedRate(logger, 0, 3000);
loader.loadFiles(args);
loggerTimer.cancel();
  • Share/Bookmark

1 comment so far ↓

#1 matt.estes on 05.23.08 at 12:42

In your defense, some of the programming language vocabulary is not nearly as nailed down as I make it seem(you get my definitions frequently, which are mostly nailed down, but you don’t see the disagreements).

I actually like Java a lot, and one of the things I hate about the closure debate is what “lesser programmers” will do with them. Cleanly adding them to the language would be a better focus than making “closures for stupid people”. But then again, I may like Java 7 less than Java 5(which I liked better than all those that came before it).

Alas, you know the cheap trick to getting around the need to declare things final? A one cell array.

Anyway, to make matters muddier, inner classes are not unrestricted closures, and one of their more subtle values was the restriction on making things final is really handy when you are dealing with multiple threads.

As a final note, sleep and that while loop don’t work how you think. You perhaps want to use a java.util.Timer, and .wait() and .notify() to accomplish the same goal(sleep(…) doesn’t block the thread, its still running in the scheduler).

I just realized how incoherent this reply is, but since I think it might have value, I’ll hit post anyway, I’ve not been sleeping well lately :) .

Leave a Comment

CommentLuv Enabled