Noel Rappin Writes Here

Java Closures

Posted on September 1, 2006


Here’s a nice item being proposed for Java 1.7: closures in Java. On behalf of all those people who actually do create entire classes just to be able to use map and other functional styles in Java, may I say, please, please, please put this in Java. (This seems a good place to link to Joel Spolsky’s wonderful programming fable “Can Your Programming Language Do This").

The proposed syntax looks like this:

public static void main(String[] args) {
 int plus2(int x) { return x+2; }
 int(int) plus2b = plus2;
 System.out.println(plus2b(2));
}

Line one of that syntax creates a closure object that takes and returns an int using what is basically Java method syntax. Line two assigns that closure to another variable using the syntax int(int) to specify the types of the signature. Line three shows that you can call the closure object as you’d expect, although notice that, unlike most Java calls, there’s no receiver object specified, and it’s not using an implicit this – it’s purely a function.

The proposal also specifies an alternate syntax for creating short closure objects – I don’t like this one as much:

int(int) plus2b = (int x) : x+2;

This is all nice, and I know I’d use it pretty much daily. Unfortunately, though, I wonder if the strict typing will wind up making the closures less useful than, say, Ruby blocks. I assume there’d be some way to tie this into the generics system so that methods that might take blocks with different type signatures would be able to convince the compiler that everything is okay. Let’s see… if I wanted to do a new method of List collect, it would be something like this.

public List<v>&lt;V&gt; collect(V(T) closure) {<br> List<v></v></v>\<V\><v><v> result = new ArrayList</v></v>\<V\><v><v><v>();<br> for (T obj : iterator()) {<br> result.add(closure(obj))<br> }<br> return result;<br>}<p>int plus2(int x) { return x+2 };<br>List<int> fred = list.collect(plus2);<br></int></p></v></v></v>

Is that right? If so, that’s certainly a lot better than we have now.

I have three quibbles and an enhancement.

Quibble 1: Like generics, what looks nice for int(int) is going to look a lot less pleasant when the signature is, say, OrderLineItem(Order, Product) or even better List<List<OrderLineItem>>(List<Order>, List<Customer>, List<Product>), which I could easily see as a real world case.

Quibble 2: Do do this right would require including support for closures up and down the standard library – all through the util classes, all through SWING, JDBC – there’s all sorts of places in the library that would be cleaned up by being able to take closures. I suspect that’s unlikely to happen quickly.

Quibble 3: The proposal says “We are also experimenting with generalizing this to support an invocation syntax that interleaves parts of the method name and its arguments, which would allow more general user-defined control structures that look like if, if-else, do-while, and so on.” I’m thinking this is more of a Smalltalk or Objective-C style? That would look odd within Java.

What I really want, though is a method literal analogous to a class literal. Something like…

Integer(MyClass) closure = MyClass.someSillyThing.method;
MyClass obj = new MyClass();
Integer x = obj.closure(3);

or even better:

MyClass obj = new MyClass();
Integer(MyClass) closure = obj.someSillyThing.method;
Integer x = closure(3);

And yes, I realize that’s basically Python bound and unbound methods. The tricky part in Java is that there might be more than one overloaded method called someSillyThing, and so I’m assuming that whatever closure object I’m creating would be able to get the right one based on the declared type (or, alternately, I suppose, dispatch properly when called). That should be doable, though. And then my Java code can look even more like Python…

Good stuff. I hope something like this gets in.



Comments

comments powered by Disqus



Copyright 2024 Noel Rappin

All opinions and thoughts expressed or shared in this article or post are my own and are independent of and should not be attributed to my current employer, Chime Financial, Inc., or its subsidiaries.