Java 7 : Add “public defender methods” to Java interfaces

At this time, we aren’t sure that the closures will be included in the Java 7 release. But these doubts have generated a new project : The “public defender methods” proposal.

This new proposal for Java 7 wants to improve the interfaces allowing to add new methods to existing interfaces. The classes implementing the interfaces doesn’t need implements these methods. The implementation of these methods are provided using static methods. This could be called virtual extension method.

To illustrate the problem the proposal want to solve, let’s take the example of reversing a List. When you have a List and you want to reverse it, you have to use the Collections.reverse() method :

List strings = new ArrayList();
//...
Collections.reverse(strings);

But there is some problems with that code. Because it’s a static method, there is no way to override it. We could imagine data structures where the reverse must be made using special algorithms to be efficient. An other problem is that the reverse() method is not in the List interface, so must learn two classes to make a simple thing as reversing a list.

The “public defender methods” give an other way to do that extending the List interface :

public interface List extends Collection {
  ...

  extension void reverse() default Collections.reverse;
}

This add a new method to the List with a default implement that use the Collections.reverse(List list) static method. The list will be passed as the first argument of the static method. So, now that you have a method reverse on the List, you can do that :

List strings = new ArrayList();
//...
strings.reverse();

This code is a lot better than the other, isn’t it ?

You can now override the reverse method providing an implementation specific to your class. But the implementation is now optional. That solve all the problems we see earlier.

To solve multiple inheritance issue a class implementing two interfaces providing a default implementation for the same method name and signature must provide an implementation of the method.

An other objective of this proposal is to “closur-ize” the Java 7 librairies. By example, we could think of a filter() method to the List interface :

public interface List extends Collection {
  ...

  extension void filter(Predicate predicate) default Collections.filter;
}

And a predicate like that :

public interface Predicate {
   boolean accept(E object);
}

That type of method can take advantage of closures. We can also imagine reduce, forEach, expand, ….

At this time, this is only a proposal, so we aren’t sure it’ll be included in Java 7 and the syntax is not definitive.

Personally, i think this is a great improvement and that will make the closures (if we have them a day) more interesting for the Java language.

If you want more information on the implementation, you could read the proposal in PDF.

 

  • jw

    This proposal is just introducing new problems.
    E.g. what happens with existing subinterfaces of List which already are defining a “reverse()” method, possibly with another behaviour or with another return type?

    And you can’t just wipe away possible problems with proxy classes, as you telled about in the proposal.

    Additionally, who will things work when introspecting interfaces via reflection?

    • Baptiste Wicht

      I think there is no probmen to override reverse with the same or covariant return type. But effectively the problem will be when overriding with incompatible return types. I think it can be possible.

      I think reflection will work the same as the compiler will create a bridge implementation in the compiled class file.

      • jw

        Thus, if I call reverse() on a list implementation compiled with an older JDK, I will get a NoSuchMethodError, because the bridge method isn’t there.
        I will not get that error if I call Collections.reverse(List). Thus we are introducing sugar for the price of serious errors.

        • Ilod

          You will not get NoSuchMethodError, the VM will generate the bridge method at runtime.
          And for overriding with incompatible return type, I think similar problem already exists :
          public class A {
          }

          public class B extends A {
          public Foo get() {

          }
          }

          If you compile B, then modify A in:
          public class A {
          public Bar get() {

          }
          }
          recompile A, you have a method in B with incompatible return type.
          I think public defenders method will work the same way than this case: if you have B b = new B();, then b.get() return Foo, but if you have A a = new B();, then a.get() return Bar.

  • jw

    This proposal is just introducing new problems.
    E.g. what happens with existing subinterfaces of List which already are defining a “reverse()” method, possibly with another behaviour or with another return type?

    And you can’t just wipe away possible problems with proxy classes, as you telled about in the proposal.

    Additionally, who will things work when introspecting interfaces via reflection?

    • Baptiste Wicht

      I think there is no probmen to override reverse with the same or covariant return type. But effectively the problem will be when overriding with incompatible return types. I think it can be possible.

      I think reflection will work the same as the compiler will create a bridge implementation in the compiled class file.

      • jw

        Thus, if I call reverse() on a list implementation compiled with an older JDK, I will get a NoSuchMethodError, because the bridge method isn’t there.
        I will not get that error if I call Collections.reverse(List). Thus we are introducing sugar for the price of serious errors.

        • Ilod

          You will not get NoSuchMethodError, the VM will generate the bridge method at runtime.
          And for overriding with incompatible return type, I think similar problem already exists :
          public class A {
          }

          public class B extends A {
          public Foo get() {

          }
          }

          If you compile B, then modify A in:
          public class A {
          public Bar get() {

          }
          }
          recompile A, you have a method in B with incompatible return type.
          I think public defenders method will work the same way than this case: if you have B b = new B();, then b.get() return Foo, but if you have A a = new B();, then a.get() return Bar.

  • M

    i see ur points llod
    On order to keep the new jdk backward compatible with the existing java libraries,
    so altering the jdk to a form that breaking the backward compatible is highly unacceptable.

    I dun think changing the widely used interface like that of the class A in ur example is not likely to be happen to the JDK. This is why we need some ways like defender method/extension method/etc… to add new mehtods to a widely used public interface in the JDK.

  • M

    i see ur points llod
    On order to keep the new jdk backward compatible with the existing java libraries,
    so altering the jdk to a form that breaking the backward compatible is highly unacceptable.

    I dun think changing the widely used interface like that of the class A in ur example is not likely to be happen to the JDK. This is why we need some ways like defender method/extension method/etc… to add new mehtods to a widely used public interface in the JDK.

  • Gonzalo Casas

    Have you checked the implementation of extensions methods on .NET?
    You import extensions methods by actually importing, so the control of what’s affected by them is on the hands of the caller, and not on the definition of the extension method.

    In Java this would translate as:

    // Defining the extension
    class CollectionExtensions {
    public extends static void reverse(List list) {
    // where the first arg is the instance on which the method is called
    //..
    }
    }

    // Using the extension
    import Sample.CollectionExtensions;

    class Foo {
    public void Bar() {
    //…
    List strings = new ArrayList();
    strings.reverse();
    }
    }

  • Gonzalo Casas

    Have you checked the implementation of extensions methods on .NET?
    You import extensions methods by actually importing, so the control of what’s affected by them is on the hands of the caller, and not on the definition of the extension method.

    In Java this would translate as:

    // Defining the extension
    class CollectionExtensions {
    public extends static void reverse(List list) {
    // where the first arg is the instance on which the method is called
    //..
    }
    }

    // Using the extension
    import Sample.CollectionExtensions;

    class Foo {
    public void Bar() {
    //…
    List strings = new ArrayList();
    strings.reverse();
    }
    }

  • http://babyjumperoo.org/ baby jumperoos

    Hi, my english isnt greatest but I feel by regulary visits of this blog it will be much better in the next time. You possess a very good wrting design that is easy to understand and can assists people like me to learn english. I will be now a regulary visitor of your blog.

    • Baptiste Wicht

      Hi.

      Thanks. It’s good to see that my english is not as bad as I think :) I make my best.

  • http://babyjumperoo.org/ baby jumperoos

    Hi, my english isnt greatest but I feel by regulary visits of this blog it will be much better in the next time. You possess a very good wrting design that is easy to understand and can assists people like me to learn english. I will be now a regulary visitor of your blog.

    • Baptiste Wicht

      Hi.

      Thanks. It’s good to see that my english is not as bad as I think :) I make my best.

  • http://www.findprefab.com Panelized Homes

    I think there is no problem to override reverse with the same or covariance return type. But effectively the problem will be when overriding with incompatible return types. I think it can be possible.