[OT] Closures?

Hi EAP folks and JBers,
Just wanted to see what you guys think of the "Closures for Java"
proposal launched on Thursday here
http://blogs.sun.com/roller/page/ahe?entry=full_disclosure
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://blogs.sun.com/roller/page/gbracha?entry=achieving_closure

I don't really get the utility of it, but perhaps somebody with a bit
more experience in Smalltalk or Ruby can enlighten me?

Robert

13 comments
Comment actions Permalink

I for one am happy to see this coming in and can't wait for it...

It definitely makes for some nicer APIs - the most common "basic" usage is with collections:

List]]> listOfUsers = getAllUsers();
listOfUsers.each (User user) { System.out.println(user.toString()l };

At least I think that's the syntax they're going for.

In smalltalk you'd have:

listOfUsers each: .

This is a fairly simple case. But then you can start extending things with your own API. So instead of say calling getAllUsers(), returning a List, then doing something with the list, you could do say:

withAllUsers( (User u) {
System.out.println(u.toString();
}

For me, it makes the readability of the program flow a lot more logical, the routine withAllUsers() may also be doing some asynchronous calls that are spread over time, instead of having to wait for all objects to be returned/created, the method could run the closure/block as soon as it gets a User object.

I'm sure others will come up with more convincing arguments as well.

The same things can be done already using anonymous inner classes, but the syntax can be quite bloated, and at least in the current implementation of java one needs to sprinkle horrible final variables or 1-element arrays into the codebase to work around scoping "problems".

0
Comment actions Permalink

I used to liked closures (and Function objects) a lot in Smalltalk.
The most used were indeed the collection ones, similar to the example you give. And indeed writing

newCollection := myCollection select:[:value| mytest ]

seems much more readable to me than the java equivalent

/* Collection myCollection */
newCollection = myCollection.clone() ; // needed to have myCollection and newCollection be the same type
newColleciton.removeAll();
for (Iterator it = myCollection.iterator(); it.hasNext();) {
Object o = it.next(); // add cast
if (myTest) { newCollection.add(o);}
}

I'm happy to see that James Gosling is backing this !!

Message was edited by:
Thibaut

0
Comment actions Permalink

newCollection = myCollection.clone() ; // needed to have myCollection and newCollection be the same type
newColleciton.removeAll();


I don't think, closures will avoid this code.

for (Iterator it = myCollection.iterator(); it.hasNext();) {
Object o = it.next(); // add cast
if (myTest) { newCollection.add(o);}
}


What about

newCollection = MyCollectionUtils.select(myCollection, new Query() {
public boolean shouldBeSelected(Object obj) {
return myTest;
}
};

Looks very clean for my eyes.

0
Comment actions Permalink

With closures, this would be

newCollection = MyCollectionUtils.select( myCollection, (Object obj):myTest);

I'm no fan of terseness for terseness sake, but I have to say that looks pretty sweet. All of the boilerplate is gone, making the underlying logic much clearer.

I'm eagerly looking forward to building automated inspections and intentions to translate those bulky anonymous inner classes into closures. I'm drooling for the day the "Refactoring" menu includes things like "Convert Collecting Loop to Filter/Map/Reduce" and "Introduce Continuation as Parameter".

The canonical book to read for why closures (and functional programming in general) is cool is The Structure and Interpretation of Computer Programs, by Abelson and Sussman. It'll expand your mind and make you a better programmer, even if Java never does get closures.

--Dave Griffith

0
Comment actions Permalink

Note also that in addition to shortening the code you posted, the closure code obsoletes a good amount of code that you didn't post, the Query interface. First-class closures means no more pointless one-method interfaces needed to abstract a callback. No more typing Runnable, Callable, ActionListener, or FileFilter, and trying to remember what the (useless) name of the method was for them.

--Dave Griffith

0
Comment actions Permalink

I would say closures in functional programming is little similar to what is being used in Smalltalk and what is proposed in Java. The most important distinction is that all variables accessed in closure in FP are immutable (in all pure languages at least), so there is no confusion for assigning the variable to the method which activation record has already passed.

While this assignment is probably going to make writing folds over data structures simpler for java programmer, the semantic burden it places on understanding underlying translation machinery is also important.

And yes, it would be fun to see how tools are going to survive this change, e.g. nonlocal transfer poses serious problems on many of our analyses (think e.g. of DFA in Idea).

0
Comment actions Permalink

Non-local transfer shouldn't be any worse than try-catch-finally. In fact, that seems to be how they are planning on implementing it. It'll degrade some analyses, but shouldn't make any impossible.

On the plus side, the "null" return type will allow some analyses to be tightened up (i.e. code after System.exit(); will be marked as unreachable).

--Dave Griffith

0
Comment actions Permalink

Dave Griffith wrote:

No more typing Runnable, Callable, ActionListener, or FileFilter, and trying to remember what the (useless) name of the method was for them.


new <Ctrl-Shift-Space> Enter?
This is one bit I don't get - Java is supposed to be easier to read than
to write, so why, 10 years after the language was rolled out, are Sun
trying to save typing effort when more people use IDEs now and so type
less now than they did 10 years ago? I don't programme in Perl for a
reason :-/
R

0
Comment actions Permalink

Non-local transfer shouldn't be any worse than
try-catch-finally. In fact, that seems to be how
they are planning on implementing it. It'll degrade
some analyses, but shouldn't make any impossible.

I did not say it will be impossible, just harder.


On the plus side, the "null" return type will allow
some analyses to be tightened up (i.e. code after
System.exit(); will be marked as unreachable).

Sorry, I don't quite understand the point, could you make some clarifications on this?

0
Comment actions Permalink

A small part of this proposal is to make it possible to declare functions and methods as non-returning. So rather than System.exit() declared as "void", it will be declared as "null". Any code after such a "null" function would be recognized by the compiler as dead (and thus illegal).

I suspect this will arise more as first class closures make it easier to write Java code in a continuation-passing style. Continuations will obviously be non-returning.

--Dave Griffith

0
Comment actions Permalink

I see it not so much a matter of decreasing typing, as removing uninformative boilerplate.

The way I see it, there's good redundancy and bad redundancy, and confusing the two is a key error in programming language design.

There's nothing wrong with redundancy or verbosity if it actually provides context, allows cross-checking, or acts as documentation. We know from information theory that redundancy is necessary for automated error detection, and I'm all about automating error detection. Having interfaces in Java, for instance, is unnecessary redundancy. You could program just fine without them, and some people do. What interfaces do is provide context, documentation, and cross-checking. The dynamic language people would argue that having any explicit types at all is unnecessary redundancy, and they are right, but in practice explicit types can be an amazing tool for enhancing program readability through context, cross-checking, and documentation.

On the other hand, there are a lot of sorts of redundancy that don't add anything to comprehensibility. For instance, all the various helper classes that each EJB 2.0 business class required didn't add anything to readability. They just repeated information that was in the business class, without adding anything. It didn't take very long for their creation to be automated out of existence with XDoclet and similar tools. That's not useful redundancy, that's just noise, and doesn't do anything to provide context, cross-checking, or documentation.

Simulating closures with anonymous inner classes requires a lot of boilerplate, which would be fine if that boilerplate actually added anything to program understandability. It doesn't. There's really no way that

executor.execute(new Runnable(){
public void run(){
System.out.println("Hello, world!");
}
};

provides any more insight into design intent than

executor.execute {System.out.println("Hello, world!"); };

--Dave Griffith

0
Comment actions Permalink

Excellent points Dave!

-


Maxim Shafirov
JetBrains, Inc
http://www.jetbrains.com
"Develop with pleasure!"


0
Comment actions Permalink

couldn't agree more :)

0

Please sign in to leave a comment.