Extension methods proposals

by Dejan Bosanac

There's a quite interesting discussion in the blogosphere about proposed extension methods feature for Java 7. The problem tackled by this proposal is how to extend an API (interface) with new methods without breaking existing implementations. The example used in a discussion is a List interface and the sort() method. In order to add another method to the existing interface, Java developers today create static utility functions. Take for example the java.util.Collections class, which is a set of static helper methods for working with collections. Among them is of course the aforementioned sort method.

12 Comments

OB
2007-12-05 05:18:51
Does this add anything other than misleading namespace conflicts? I can't see the benefit other than leaving out one little namespace prefix as Collection.sort - which I prefer
Dave
2007-12-05 09:26:47
Warth et al Expanders.


http://www.cs.ucla.edu/~todd/research/expanders/

puppetluva
2007-12-05 15:25:19
I think that this will make apps harder to comprehend and debug- very much in the same way that static imports do.
Greg M
2007-12-05 17:25:17
Seriously, bite the bullet and add stand-alone functions. This deficiency is a show-stopper for so many kinds of clean abstraction in Java. It would be kind of admitting that OOP is not good enough, but surely it's time for that? Java use is driven by entrenchment and library/tools support these days, I don't think anyone is still under the impression that the language itself is "good enough".
WW
2007-12-06 00:03:27
Which problem are we trying to solve here?


Isn't sort(list); more than sufficient? And isn't sort my list more natural than list my sort?


It seems to my that the benefit is extremely small, while the added complexity is huge (certainly when compared to the benefit itself).

bwtaylor
2007-12-06 15:46:33
I like it. What are all you folks afraid of? This is infinitely better than mixins in dynamic language or bytecode enhancement, each of which change the behavior of a class at runtime. This is a compile time concept, and tooling support shouldn't be a problem.


I use the existing static imports all the time and none of the supposed objections have any downside other than being different. My code is a lot more readable (assuming I name my methods well). I read Flannigan's article and thought "yes, it has the obvious behavior when you do that". If you want to know what sort(list) does, read your imports, (or hit F3 on it in Eclipse). I like list.sort() event better because it is more OO: objects have behavior. All this lets me do is to specify a behavior using an intuitive and well defined shorthand.

Tom
2007-12-06 17:38:29
I think static extension methods would be great. Any stateful information can be handles by a ThreadLocal. Using annotations wouldn't be bad either, although too many annotations just make things more confusing.


Groovy's categories are nice, but I don't like the extra level of indentation. Usually I will add extension methods directly to the MetaClass.


The .do... is misleading, because it looks like accessing a field on an instance. And PLEASE please please don't make a two character operator. Good god. And really -- this is all syntactic sugar that the compiler will just take out anyways. But good to have nonetheless.

Howard Lovatt
2007-12-06 18:22:57
I am not a fan of the syntax - it looks like a dynamic dispatch call but it isn't and it also has a narrow use case (statically imported static methods). An alternative might be a with statement (like Pascal). You could use a with keyword or the symbol ->. For example suppose filter was a statically imported method that worked on a list:


list -> filter(test);


The idea of the -> is that it replaces the first argument of a call, including the hidden this. It also can be applied to a block. AddAll is a method in List already, so the following:


list -> { addAll(list2); addAll(list3); };


Puts all the lists into list. The -> operator would return as its value the result of the last operation. This would allow it to be used in a builder pattern. EG


House h = new Building() -> { add(doors); add(windows); makeHouse(); };


Re the builder pattern, there is another Java 7 proposal for this.


The with clause idea outlined above is similar to Stephen Colebourne's .do. proposal but additionally allows application to a block. Many syntax variations would be possible, e.g. with keyword, a different symbol. But I think the semantics of a with block that returns a value would be a useful addition.

Tasos
2007-12-07 07:09:44
"What are all you folks afraid of?"...


I use Java because I can think like a human and not use my brain to think like a compiler...
As someone wrote in a forum once, it becomes "harder to pick up the high-level stuff as you're wasting mental energy on extra low-level cognitive processing.".
And then there is also the issue around maintenance...


I've never understood the benefit case for static imports anyway.
What is the saving? A once-off typing saving? IDEs could help here. (Importing static constants may have readability benefits.)
The cost? Every time the code is read, the reader needs to mentally confirm whether the method call is static or not and which method is actually called.
Have a look at the excellent "Java Puzzlers" book (71: Import duty) for a related discussion.


"clever" code doesn't "rub off" on its authors... ;-)

tubby
2007-12-08 19:58:48
This has to be the worst idea in Java history. Talk about sweeping a problem under the carpet - or papering over an existing problem. The API writer is now playing architect for the users of his/her library. How about concentrating on the JVM and stop peddling these ridiculous extension to the language. That's what Groovy is for.
reza
2007-12-09 05:33:15
hi
java.util.Collections.sort() dosn't work correctly with
UTF 8 String Values
Howard Lovatt
2007-12-13 14:32:44
I have blogged about an alternative, with clauses:


http://www.artima.com/weblogs/viewpost.jsp?thread=220783


Typical usages are:


list -> synchronizedList() -> sort();
list -> { add( 1, "A" ); add( 2, "B" ); };
Home home = new Builder() -> { setWindows( windows ); setDoors( doors ); makeHome(); };