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.
Here’s a simple example:
public class Extension {
public static void main(String[] args) {
ArrayList list = new ArrayList() ;
list.add("123");
list.add("678");
list.add("456");
java.util.Collections.sort(list);
System.out.println(list);
}
}
Here we have defined a list and used static sort method of the java.util.Collections class to sort it. As a result we get the following output
[123, 456, 678]
Since Java 5, we are able to do static imports so we can do this in a bit more elegant way. The previous example can be rewritten as follows
import static java.util.Collections.sort;
public class Extension {
public static void main(String[] args) {
ArrayList list = new ArrayList() ;
list.add("123");
list.add("678");
list.add("456");
sort(list);
System.out.println (list);
}
}
There are many things about static import feature that are declared as “controversial” by developers, such as shadowing of imports by locally defined static methods and importing more then one static method with the same name (look at this post by David Flanagan for more info).
The idea of “extension methods” for Java 7 is based on static imports and it adds another “feature” for such methods. It all started with the
initial Neal Gafter’s proposal. The proposal is to enable usage of statically imported functions as methods of the original interface. So instead of
sort(list)
we can use it in a more natural way
list.sort()
Some of the potential problems of this use-site extension methods approach as called and spotted by Peter Ahe are the same as with ordinary statically imported methods. Additionally, it transparently enables end users to extend final classes which could be one more source of bugs in the applications.
That’s why he proposes the declaration-site extension methods mechanism which means that API developer must specifically mark methods that could be extended in this way. For example
void sort() import static java.util.Collections.sort;
Stephen Colebourne joined the discussion arguing that Peter’s approach prevents users to extend the API which is probably the most important usage of this mechanism.
He proposed usage of the special syntax for using extension methods, such as
list.do.sort();
or
list->sort();
and that is probably better to annotate methods we want to be extensible (if we must) since it will give more flexibility over Peter’s approach, such as
@ExtensionMethod
public void sort(List list) { ...}
But this mechanism changes the language syntax, which is probably something Neal wanted to avoid in the first place.
Finally, there are mechanisms that other languages use for this kind of tasks (but of course require language syntax change). For example, in Groovy you can use Categories to do this. Take a look at this example.
class EnhancedInteger {
static boolean greaterThanAll(Integer self, Object[] others) {
greaterThanAll(self, others)
}
static boolean greaterThanAll(Integer self, others) {
others.every{ self > it }
}
}
use(EnhancedInteger) {
assert 4.greaterThanAll(1, 2, 3)
assert !5.greaterThanAll(2, 4, 6)
assert 5.greaterThanAll(-4..4)
assert 5.greaterThanAll([])
assert !5.greaterThanAll([4, 5])
}
In any case I think this is an important topic (which is something you can see by the number of comments found on aforementioned blog posts) and it is important to find a balance between the feature and how it will affect the syntax. I think it will all end up with Neal’s original proposal with note to developers “use with care”. But one thing is certain, it is great to see this kind of topics discussed in blogosphere this early in the process. What’s your take on this?



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
Warth et al Expanders.
http://www.cs.ucla.edu/~todd/research/expanders/
I think that this will make apps harder to comprehend and debug- very much in the same way that static imports do.
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".
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).
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.
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.
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.
"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... ;-)
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.
hi
java.util.Collections.sort() dosn't work correctly with
UTF 8 String Values
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(); };