Closures in Java: another proposal
I am glad that none of the proposals for Closures have been chosen for Java 7. If you don't know, their code names are: BGGA, CICE, and FCM. Why? Because they all suck. Here is my proposal: to introduce alternative syntax for defining an anonymous inner class that extends Object and implements an interface with only one method, with the following construct:
{ arg1, arg2,... argN => statements; }
or { statements; }
if the method doesn't have any parameters.Example 1:
SwingUtilities.invokeLater({field.setText("Hello");})
which is equivalent to:
SwingUtilities.invokeLater(new Runnable() {
public void run(){
field.setText("Hello");
}
});
Example 2:
List<String> list = ...;
Collections.sort(list, {a, b => return a.compareToIgnoreCase(b);});
which is equivalent to:
List<String> list = ...;
Collections.sort(list, new Comparator<String, String>() {
public int compare(String a, String b) {
return a.compareToIgnoreCase(b);
}
});
11 Comments:
Your specification leaves out almost all the important details of a language specification. When passed as an argument to a method, how does the compiler perform overload resolution to select the called method? How does it infer the (untyped) closure parameter types? Which of these is performed before the other?
1. "When passed as an argument to a method, how does the compiler perform overload resolution to select the called method?"
Very easy - by the type of the argument. There is no need to perform any "overload resolution" because in my proposal, the type of the argument must be an interface with one method.
2. "How does it infer the (untyped) closure parameter types?"
Closure parameters are simply the names of the corresponding method parameters which have their types defined in the interface.
@Alex - the type of *what* argument? If the name of the method being called is overloaded, you have to decide which overload you're taking the type of the argument from. Are you proposing that closures can't be used in arguments to methods that are overloaded?
Oh, thanks for pointing that out, Neal. I didn't think about overloading in that context. Ok, in case if there is ambiguity we could add an explicit typecast just before the closure, much like you would before a null that you pass to an overloaded method.
For example, you have two methods in class X: call(Callable<T>) and call(Runnable). Then invoking call(Runnable) method with a closure parameter would look like this:
xxx.call((Runnable){doSomething;});
@Alex: I didn't ask how a programmer would "work around" an ambiguity, I asked what happens (in the absence of a cast). Is it an error? What exactly is the error? (Your "specification" doesn't appear to describe any possible errors)
In the absence of a typecast, there will be a compile-time error.
Example:
xxx.call({doSomething();})
will generate the following error:
reference to call is ambiguous, both method <T>call(java.util.concurrent.Callable<T>) and method call(java.lang.Runnable) match
What are the rules for deciding which ones "match"? Presumably the "body" of the "closure" might match some types and not match other types. So that are the rules?
Also, some of the methods in the overload set might be generic - that is, they might have type parameters - and those type parameters might be used as part of the declaration of the method parameter that is to "match" the closure. How do you decide, in that case, whether or not the closure "matches"?
1. "What are the rules for deciding which ones match?"
Method parameter will be considered a match if its type is an interface with one method. If there is more than one matching method then a compile time error described above will be generated.
The compiler won't attempt to resolve method signature based on the number (or types) closure parameters. This part is debatable but I don't consider it an issue of principle.
2. "Also, some of the methods in the overload set might be generic ... How do you decide, in that case, whether or not the closure "matches"?
If the interface is generic, an explicit typecast is needed, too.
Example:
xxx.call((Callable<String>){return "Hello";});
Another possible use of a closure is in an assignment:
Callable<String> callback = {return "Hello";};
I just discovered that my "proposal" is actualy CICE! What a shame.
OK, it's a little different than CICE because you don't have to use class declaration in many cases which makes it more elegant and that's what the purpose of the closures is -- to make certain code constructs more elegant.
Post a Comment
Subscribe to Post Comments [Atom]
<< Home