I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Public Defender Methods: A Good Idea?

06.02.2010
| 9243 views |
  • submit to reddit
While catching up on the latest news from Java 7, I read this article from Baptiste Wicht, which explains a new proposal (pdf). The proposal itself is fairly straightforward, addressing the problem that once an interface is published, methods cannot be added without breaking the interface. In particular, this proposal would allow the Collections interface to take advantage of closures, a first draft of which is included in JDK7. Baptiste for provides a very clear explanation of the proposal, here is a summary

At the moment, if you need to extend functionality, you can create static methods, much like Collections does with it's reverse method. This has the issue that you cannot override the reverse method for your own collections implementation. And more to the point, wouldn't it be nice to have a reverse() method in the List itself?

The proposal would result in syntax that looks as follows:
public interface List<T> extends Collection<T>
{
public int size();
// The rest of the existing Set methods
extension void reverse() default Collections.<T>reverse;
}

This would mean that you could extend the reverse method yourself if you wish. If you don't want to, the functionality would default to calling another methods (in this case Collections.reverse()).

Is this something you'd want to do? I don't think I'd like to see the addition myself. I prefer simple, unambiguous code. If I break an interface, clients of that interface need to deal with the change. At least it makes it very clear that the contract has changed.
Tags:

Comments

Ricky Clarkson replied on Wed, 2010/06/02 - 5:22am

The point is that the alternative is poor; utility methods sprinkled in arbitrary classes that you cannot discover through code completion. It's hard to argue that Collections.sort(list) is in any way more readable than list.sort().

I'm not sure your example is a good one; reversing a Set, which is a collection with no defined order.

Regarding breaking interfaces, that just isn't an option for Java. Backward compatibility, at source and binary level, has to be maintained.

James Sugrue replied on Wed, 2010/06/02 - 7:42am in response to: Ricky Clarkson

Hi Ricky

That's a good point - a bad example, which I'll update now. And of course, you're right about breaking interfaces for a language.. 

What do you think of the proposal in general?

James

 

Mladen Girazovski replied on Wed, 2010/06/02 - 7:48am

Specifying an implementing Method in an Interface smells fishy to me, even if its just an default implementation.

Artur Biesiadowski replied on Wed, 2010/06/02 - 7:54am

It is only sane way to allow extending existing collection libraries with methods using lambdas (jdk 7 closures) - at the same time allowing ploymorphism for those methods.

Current solution for adding methods was static utility classes. I do not have big issues with style - using static import, you end up with sort(list) versus list.sort(), which is not really a bit issue. What is a a problem is that you are getting same sort implementation for both ArrayList and LinkedList - which is a missed place for optimalization. With lambdas, we can expect explosion of collection-related methods and having all of them conforming to lowest common denominator would be a waste.

 

Joerg Wassmer replied on Wed, 2010/06/02 - 8:17am

The proposal is breaking interfaces, thus it is introducing syntactic sugar for the price of serious errors.

Michael Bien replied on Wed, 2010/06/02 - 3:05pm

its a way to evolve the platform without breaking client code. It is not a feature which most of us should use in the programs we write. Its rather a hack to solve some corner cases of modularity.

E.g eclipse used interface numbering to evolve the platform. (e.g IFoo10 extends IFoo9) ... just a workaround for not having something like extension methods.

Cloves Almeida replied on Wed, 2010/06/02 - 7:31pm

I read the specification and sounded good. Maybe for those that want to enforce strict compatibility, could have a '-noDefenderClasses' runtime flag. IMO "breaking interfaces" is not that much of an issue in real world.

Could someone provide an example where such construct would be an issue?

 

Dimitar Dimitrov replied on Fri, 2010/06/04 - 2:47am

This is actually one way to implement extension methods. There was a discussion some time ago, proposing alternative way declaring the mixins at the usage site. I can't remember the actual syntax, but the usage was something like this:

class MyCollectionUtils {
  public static void myExt(Collection that, int arg) { 
    do something... 
  }
}

Collection<String>+Collections+MyCollectionUtils foo = new ArrayList<String>();
foo.myExt(5); 
foo.unmodifiableCollection();

Artur Biesiadowski replied on Fri, 2010/06/04 - 5:26pm in response to: Dimitar Dimitrov

@Dimitar

Was that mixing idea allowing ArrayList to overwrite myExt with more optimized version directly on ArrayList? If not, it is just a syntax sugar around not calling MyCollectionUtils.myExt(foo,5), which is NOT what defender methods are about.

Dimitar Dimitrov replied on Sun, 2010/06/06 - 7:58pm in response to: Artur Biesiadowski

@Artur

No, the proposals are not feature-equal (otherwise they wouldn't be separate proposals), but they are addressing the same use case. The use case given was that we need to extend old APIs in non-breaking way and to allow for static discoverability of the new methods for IDE code completion.

I'm not against the proposal, I just don't see why is it important to allow overriding of the extension methods. An alternative would be to mix in different static method

The public-defender method proposal in essence puts the control on the library provider side. The augmentated-declaration proposal, mandates that the API user specifies what functionality they want to tack on top of the interface provided by the type (note that you would want something like typedefs if one starts using it). As such they are not exclusive, though they have overlap in the intended usage.

From my point of view, a major downside of the proposal is that it complicates the concept of interface and arguably reduces orthogonality in the language and makes Java look even more Frankenstein-y (ever tried teaching nested/inner/annonymous-classes to newgrads?). In the end, the interface will be defined as "class without fields that can be multiply-inherited" - in such case, I'd rather drop the concept and say that any class without fields can be multiply inherited. Of course this is not possible because of backwards compatibility concerns, so that's why I'm bringing back some relevant previous proposals for re-evaluation.

Here are more details:
  • http://gafter.blogspot.com/2007/11/closures-prototype-update-and-extension.html
  • http://digital-sushi.org/entry/declaration-site-extension-methods/

Sven Efftinge replied on Thu, 2010/06/17 - 3:06pm

I wonder why the syntax is so special. Couldn't we just allow implementation bodies for interface methods?

interface Foo {
   String bar(String baz) {
       ....
   }
}

That would be much more familiar and much less restricting. Also we could avoid all these unnecessary keywords.

Maybe interfaces would than look too much like abstract classes...

If Java had not introduced the notion of interfaces in the first place but instead allowed multiple inheritance with a method resolution similar to Scala's Traits, we had the same power but it would have been conceptually much simpler and more orthogonal, wouldn't it?

Ramon Rivas Diaz replied on Thu, 2010/07/22 - 11:28am

Why not using annotations? No new keywords needed!

public interface List extends Collection {
    int size();
    @DefaultImpl(Collections.reverse) void reverse();
}

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.