Declaration-Site Extension Methods

Neal Gafter and others are suggesting to add extension methods to the Java programming language. To be clear about Neal’s proposal, I will call it use-site extension methods. I call them so because the user specifies which extension methods are to be used.

To be concrete, let me repeat Neal’s example of adding a sort() method to java.util.List:

import static java.util.Collections.sort;

List<String> list = …;
list.sort();

A clear benefit to this is that it builds on an existing language construct, static import. And as such, it may seem to be a simple extension. Unfortunately, in Java, nothing is simple. By itself, static import has a number of limitations. For example, you cannot import a method with the same name from different types. [update: actually you can, see also the comments.]

Another potential issue is source compatibility: currently, adding a public method to a final class is a source compatible change. However, if you add use-site extension methods, this is no longer true. A client of the final class could be extending it with a method with the same name as the new method. Imagine that the signature of the added method is compatible with the extension method, in this case, the compiler will not flag this as a potential error, instead it will silent change what method is called. This is a potential for subtle bugs.

An alternative is declaration-site extension methods in which the library designer specifies extension methods when declaring the type to be extended.

For example, instead of having each user of java.util.List import a sort method, the interface could declare that it is extended by java.util.Collections.sort:

package java.util;
interface List<E> … {
  …
  void sort() import static java.util.Collections.sort;
  …
}

This will instruct the compiler to compile:

java.util.List<String> list = …;
list.sort();
as if the user had written:
java.util.List<String> list = …;
java.util.Collections.sort(list);

Declaring sort within java.util.List<String> should only affect the compilation of clients of the interface. The compiler must record that the interface is extended by adding a new kind of attribute to the class file, but this should be defined to affect neither the calculation of default serialVersionUID nor how methods are looked up by the JVM.

Acknowledgements

Alex Buckley coined the terms use-site extension methods and declaration-site extension methods inspired by Thorup and Torgersen’s use-site variance. See also, Adding Wildcards to the Java Programming Language.

44 Responses to “Declaration-Site Extension Methods”

  1. Neal Gafter Says:

    Neat idea. I like it. The version I presented is only a strawman. I described both the simplest and the most full featured versions of the feature I am aware of. Your suggestion make a lot of sense as a practical middle ground.

    A nit: you say “you cannot import a method with the same name from different types.”

    Actually, you can. They overload.

  2. Peter Ahé Says:

    Actually, I think it is unspecified what happens. JLS3 15.12.1 has a false assertion: there must be an enclosing type declaration of which that method is a member. However, this is not true for static imports.

  3. Jaroslav Tulach Says:

    On OOPSLA 2006 I’ve heard and relatively liked a similar proposal:

    This paper introduces the expander, a new object-oriented (OO) programming language construct designed to support object adaptation. Expanders allow existing classes to be noninvasively updated with new methods, fields, and superinterfaces. Each client can customize its view of a class by explicitly importing any number of associated expanders.

  4. Tom Hawtin Says:

    void sort() import static java.util.Collections.sort;

    Why not just allow a body:

    void sort() { java.util.Collections.sort(this); }

    where List.sort would become a non-virtual method, keeping the same method lookup as the import static syntax. (And ignored for the purposes of calculating default serialVersionUID.)

  5. Patrick Wright Says:

    Neal’s suggestion (however incomplete) has the advantage that the extension methods are not necessarily part of the JDK. In your approach, the List interface must be updated, then closed for further updates until the next JDK release. In Neal’s approach, I can attach any method to List that I want, for any project that I work on. Obviously there will be some methods that the core-libs dev team decides will be generally useful, though as the discussion around “humane” APIs some time back showed, it will be hard to agree on what the limited set should comprise (see http://martinfowler.com/bliki/HumaneInterface.html).

    What I like about Neal’s approach is that we can package different utility classes with extension methods for lists (or strings-does this need to be limited to extending interfaces? what about final classes?), to make them more convenient/friendly to use, in particular in cases where we run up against the limitations of the class API–for example, if doing a lot of String manipulation in one section of our code, we may want to add some convenience methods to simplify and clarify things (like the recent request for rtrim and ltrim in String), and in those cases we pick the extensions library that we think fits the best in that particular situation.

    Regards
    Patrick

  6. Axel Groß Says:

    Hey Peter!
    Could you please clarify how you would declare the interface?

    I mean as I want to add methods to the class/interface of somebody else, I can’t directly edit the original source (of e.g. java.util.List) and I have to put my metadata somewhere else.
    If I got you right, you suggested to write a ‘parallel’ java file (same package declaration and class name as original), right?

  7. Peter Ahé Says:

    Tom,

    You are suggesting another possible syntax for declaration-site extension methods. Depending on your goals, you could prefer either one. My syntax is just a suggestion, but I was deliberately trying to make it look different from a regular method. Your suggestion may require some slightly more complicated semantic rules.

  8. Peter Ahé Says:

    Patrick,

    The danger of use-site extension methods is that it creates many dialects of the Java libraries. I’m suggesting an alternative. An alternative, that happens to be compatible, that is, you can have both use-site and declaration-site extension methods. Indeed, my personal opinion is that declaration-site extension methods is a better fit for Java.

  9. Peter Ahé Says:

    Axel,

    I am not suggesting that you write a parallel Java file. I suggest that the author of List decides how to extend the interface. This is a key difference between use-site and declaration-site extension methods.

  10. Peter Ahé Says:

    Jarda,

    I think you are referring to the same paper as Neal did. From the abstract, it seemed to be use-site only. Am I wrong? Do you recommend that I read the full paper?

  11. Peter Ahé Says:

    Neal,

    I had an expert look at the JLS, and, of course, you were right. There is a minor bug in JLS3 §15.12.1. However, §15.12.2 says: In addition, if the method invocation has, before the left parenthesis, a MethodName of the form Identifier, then the search process also examines all methods that are (a) imported by single-static-import declarations (§7.5.3) and static-import-on-demand declarations (§7.5.4) within the compilation unit (§7.3) within which the method invocation occurs, and (b) not shadowed (§6.3.1) at the place where the method invocation appears.

  12. Talden Says:

    What about adding to the static import syntax for use-site extension?

    static import java.util.Collections.sort : List.sort();

    This alleviates the constraints of a non-utopian period between API releases and allows extensions that the API designer may very well never add (domain requirements of a particular project perhaps). This syntax helps remove the visual ambiguity of name-identical static imports intended for different interfaces.

    I think that the suggested declaration-site solution should also be included - both have their place and, as stated, declaration-site is the preference, if we’re to contain the rate of dialect divergance.

  13. Stepan Says:

    Why not just allow non-abstract interface methods?

  14. Axel Groß Says:

    Peter, so you suggest to wire some methods into interfaces? Like Mix-ins?

    Similar to what is possibly with abstract classes, just for interfaces with a neater syntax?
    So whats possible right now:

    package java.util;
    abstract class AbrastList … {

    final void sort(){ java.util.Collections.sort(this); }

    }

  15. Peter Ahé Says:

    Stepan,

    Non-abstract interface methods lead to multiple inheritance and all its problems.

  16. Peter Ahé Says:

    Talden,

    You suggestion fits nicely with type aliasing as I described on my Java SE 7 wish list. Personally I would prefer to use “as” instead of a colon.

  17. Peter Ahé Says:

    Axel,

    My suggestion is not like mixins. Mixins are applied to classes (not interfaces) and never lead to multiple inheritance.

    Use-site extension method and declaration-site extension methods have in common that they provide syntactic sugar for calling static methods. The difference is who can specify what sugar is available: is it the user or the author of the library.

  18. Mark Mahieu Says:

    Peter,

    Extension methods could be a big win for Java :)

    Your suggestion deals with the two primary issues I had with Neal’s strawman:
    1) the ‘accidental’ pollution of the importing class’s namespace, allowing sort(list) when list.sort() is all that’s desired.
    2) if my interpretation was correct, the ability to add methods to any type, which could well lead to a proliferation of ‘clever’ but ultimately confusing libraries adding methods to Object, String etc (which can be useful in some languages, admittedly).

    The mention of multiple inheritance is interesting - I wonder whether programmers would start writing interfaces containing only extension methods (possibly even defined in and then imported from a nested class), just so that they can then create a class which implements multiple such interfaces, thereby attaining some of the capability of multiple inheritance. Maybe that’s not such a bad thing - since there’s no instance state associated with extension methods we wouldn’t see the mess that real multiple inheritance can result in.

    I’m also wondering how reflection should work with extension methods, particularly in terms of a method’s parameters - does List.sort() have no parameters, or one? Is a java.lang.reflect.Method describing List.sort() equal to one describing Collections.sort(List) (perhaps this is the same question). Again though, I think this would be easier to deal with consistently in the case of declaration-site extension methods.

  19. Peter Ahé Says:

    Mark,

    Regarding reflection, my thought was that extension method should not show up as methods. However, it would make sense to add getExtensionMethods() to Class. This method should return an array (sigh) of something similar to java.lang.reflect.Method.

  20. Stepan Says:

    Peter, multiple-inheritance problems can be clearly solved. For example, compiler could force class to specily exact implementation of method in case of ambiguity:

    interface A {
    void f() { … }
    }

    interface B() {
    void f() { … }
    }

    class C implements A, B { } // compiler error: ambiguity

    class C implements A, B {
    void f() { A.this.f(); } // OK
    }

    actually exact resolution of ambigity will be rarely needed.

    BTW interfaces should not have fields, of course.

  21. Peter Ahé Says:

    Stepan,

    Java was designed without multiple inheritance, and I think that was a very wise decision. Interfaces is one of the greatest features of Java, and I’m not proposing to ruin that by adding multiple inheritance.

    It is well-known that you can work around all the downsides of multiple inheritance; C++ demonstrates that. However, it is these work-arounds themselves I consider too high a price to pay.

    The problem, I’m trying to solve with extension methods, is to be able to add methods to an interface in an backwards compatible manner. I believe this was also what prompted Neal to suggest extension methods. Your example is not backwards compatible; assume this was the original situation:

    interface A {}

    interface B() {}

    class C implements A, B {}

    Now add f methods to both A and B. C will fail to compile in violation of source-compatibility. Even if this is a rare situation, I’ll bet it would occur at least once in every large Java program.

    BTW: adding fields to interfaces would be the next logical request from some people in favor of having non-abstract methods in interfaces. It is a slippery slope.

  22. Josh Bloch Says:

    I view this whole line of design (”Declaration-Site Extension Methods) as fundamentally misguided. The whole idea of the Extension Method proposal in the JSR was to allow clients to extend types from the outside (without modifying them in any way). Moreover, the proposed solution does not appear to be in the spirit of the JSR (”small language extensions to improve the clarity, safety, and ease-of-use of the language, without adding appreciably to its complexity”).

  23. Peter Ahé Says:

    Josh,

    Thank you for your comments.

    I respectfully disagree with your point of view. My preference would be not to allow clients to extend types from the outside because I’m concerned about compatibility. That being said, the two proposals are not mutually exclusive.

    Equally respectfully, I disagree with your assertion that declaration-site extension methods are not in the spirit of the JSR. I believe it meets all requirements you have quoted at least as well as use-site extension methods. In fact, one could argue that use-site extension methods does not improve the clarity of the language.

  24. Josh Bloch Says:

    Peter,

    Hi! I agree that the two proposals “are not mutually inconclusive.” In fact, they accomplish rather different things. The JSR draft says this: “With extension methods, clients. can designate utility methods to act as if they were members of the interface (or class).” The point was to allow clients to leverage existing types, whether classes or interfaces, without change to those types. Your proposal does not achieve this, nor does it try to. You argue that it’s a bad idea, and you may be right, in which case we should scrap the idea.

    That said, you proposal is undeniably more heavyweight, hence less in the spirit of the JSR draft. To the best of my knowledge, nothing else in the draft requires any change to the class file format (or the way in which the JVM processes class files). I suspect that your proposal would require this.

    Finally, your proposal must be regarded as a fundamental change to the nature of interfaces in Java. I believe that interfaces are the heart and soul of the language, hence am reluctant to mess with them.

    Josh

  25. vhi Says:

    For an example of mixins well done, you may be interested in taking a look at how “traits” are done in Scala.. Traits in Scala are something like interfaces in Java, without the ability to have state, solving the main issues with multiple inheritance…

  26. Peter Ahé Says:

    vhi,

    If you’re really interested in mixins, you should have a look at Mixins in Strongtalk and Strongtalk.

  27. Andrew Thompson Says:

    Speaking of the prevalence of interfaces in Java, I’m somewhat disappointed these proposals don’t allow the introduction of new super-interfaces for types.

    Let’s say for the sake of argument I needed to create an interface for the two binarySearch() methods in Collections:

    public interface Searchable {
    public int binarySearch(E key)
    public int binarySearch(E key, Comparator c)
    }

    Using Peter’s proposal we assume I have the ability to change java.util.List, so I write:

    interface List implements Collection, Iterable, Searchable { …
    void binarySearch(E key) import static java.util.Collections.binarySearch;
    void binarySearch(E key, Comparator c) import static java.util.Collections.binarySearch;
    }

    And then write code that works on List or anything else that’s Searchable:

    int search(Searchable toSearch, E toSearchFor) {
    // here we do something useful like checking a cache first … then

    return toSearch.binarySearch(toSearchFor);
    }

    and call it

    List es = …
    E e = …
    int index = search(es, e);

    If there were a lot of methods, some sugar like this might be preferable:

    interface List implements Collection, Iterable, Searchable static Collections { …

    Which would mean any methods in Searchable would have to be statically locatable in Collections. Of course, that would limit you to one source of static methods per interface, but that might be a good thing!

    In the real world, I don’t have the ability to change java.util.List, which shows both the strength and the weakness of the use site proposal which is far more democratic in that an application developer can the same power as a library author, but it is also much more limited.

    Can we introduce super interfaces to types at the use site? Given a class SearchCache with the same method as above

    public int search(Searchable toSearch, E toSearchFor) {
    // here we do something useful like checking a cache first … then

    return toSearch.binarySearch(toSearchFor);
    }

    When one wants to use it in some other file SearchUser.java:

    import java.util.List implements Searchable static Collections;

    class SearchUser {

    void useIt() {
    List es = …
    SeachCache sc = …

    int index = sc.searchContainer(es);

    }

    My gut reaction is the compiler could type check this. That amounts to a check that a single suitable method exists in List OR static method in Collections for each method in Searchable. That’s actually a key point… the method the introduced interface requires could come from List.

    The issue is in order to have modular compilation and be able to pass ‘es’ into SearchCache some form of code generation would be required at the call site to create an adapter that would implement List and Searchable and do the appropriate method forwarding. As a separate instance it’d be subject to the usual problems with identity (==)

    Am I right or is there some known implementation trick that would get around this?

  28. Roel Spilker Says:

    Peter,

    1) If List defines the sort methed, the way you suggest, wouldn’t it break existing List-implementation that already have a sort method?

    2) Do you see it possible to use this feature to provide default-implemantations? So a specialized list can implement it’s own sort algoritm using some sort of @Override annotation. That way it could be used as a substitute for Josh Bloch’s MapPlus problem (can find the link using Google :) )

    The problem is that ConcurrentHashMap has a putIfAbsent method and Map doesn’t. It would be preferable to add it to the Map interface, but that’s impossible. So instead a new interface, for now called MapPlus, can be introduced containing the extra method, and all JDK map implementation can implement this extra method.

    Using the declaration-site extension methods including overrides would be a great way to fixthis problem.

  29. Peter Ahé Says:

    Roel,

    1) Good point. I forgot to put my thoughts on that in the original post. Basically, my thoughts would be that a warning should be issued in situations that could be confusing. Assume that MyListWithSort is a List implementation with a sort method, assume MyListNoSort is a List implementation without sort. Furthermore, assume we added the declaration-site extension method to List as described above. Then:

    MyListWithSort l1 = new MyListWithSort();
    MyListNoSort l2 = new MyListNoSort();
    List l = l1;
    l1.sort(); // Calls MyListWithSort.sort and issues a compile-time warning
    l2.sort(); // Compiles to java.util.Collections.sort(l2)
    l.sort(); // Compiles to java.util.Collections.sort(l)

    Furthermore, recompiling MyListWithSort would result in a compile-time warning.

    2) No, I do not think this feature could be used to provide default implementations. That would cause the default serialVersionUID to change and require changes to how the JVM looks up methods.

  30. Alex Miller - Java 7 Roundup (November 30th) Says:

    […] Peter Ahé […]

  31. Howard Lovatt Says:

    I am with all the people who say turn interfaces into traits. Traits work really well and solve this problem. The most basic form of a trait is to allow interfaces to have method definitions and if there is a conflict then you have to override the method. EG

    interface X { int foo() { return 1; } }

    interface Y { int foo() { return 2; } }

    class XY implements X, Y {
    public int foo() { // must write a foo to resolve ambiguity
    return X.foo();
    }
    }

  32. night tale » Extension methods proposals Says:

    […] 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 […]

  33. Peter Ahé Says:

    Howard,

    I don’t think it is realistic to add anything like traits to Java at this point. However, if one were to consider the possibility, I would vote for mixins instead (interfaces remain untouched, unlimited code sharing, single inheritance, and state). Turning interfaces into traits would be the worst possible outcome, and your motivating example shows that it would be full of source and binary compatibility issues.

  34. Howard Lovatt Says:

    Peter,

    I think your concerns can re. implementation can be addressed. Consider:

    interface X { int foo() { return 1; } }

    interface Y { int foo() { return 2; } }

    class XY implements X, Y { public int foo() { return X.foo(); } }

    This can be translated automatically by the compiler into:

    interface X {
    int foo();
    public static class $Trait { public int foo() { return 1; } }
    }

    interface Y {
    int foo();
    public static class $Trait { public int foo() { return 2; } }
    }

    class XY implements X, Y { public int foo() { return X.$Trait.foo(); } }

    For classes that aren’t ambiguous, and hence the user doesn’t write a foo, the compiler supplies the methods automaticallye.g.:

    class XX implements X {}

    Becomes:

    class XX implements X { public int foo() { return X.$Trait.foo(); } }

    I have considered adding traits to my own pet project: pec.dev.java.net - hence I already knew a possible translation.

    Howard.

  35. Howard Lovatt Says:

    Oops I said the *compiler* automatically supplies the methods. I meant the *class loader*. Sorry.

  36. Peter Ahé Says:

    Howard,

    I do believe that it is possible to implement traits. I just don’t think it would be a good idea to implement traits, because I’m concerned about compatibility and I like mixins better :-)

    Your examples break at least source compatibility.

  37. Howard Lovatt Says:

    Re. use-site extensions, Josh Bloch is of course right in saying that the trait/mixin/declaration-site aren’t as flexible [NOTE from Peter: Josh did not express an opinion on traits or mixins]. But I am not totally convinced about the extension mechanism as proposed - maybe I need to know more about it. My particular concerns are:

    1. They look like they do dynamic dispatch, but they don’t.
    2. They have a limited use case - statically imported static methods

    Perhaps -> could be used and that this notation is for the first argument of *any* method regardless of how its name is made available and this first argument *includes* the hidden this of instance methods. Therefore you could write:

    list -> filter( test1 ) -> filter( test2 ); // static void filter(List, Predicate) is statically imported

    list1 -> addAll( list 2 ) -> addAll( list3 ); // addAll(List) is an instance method in List

    The above notation is similar to the builder notation, also proposed for Java 7 (new X().setProp1().setProp2() where the props return void) and is meant to combine the two proposals. The same as the builder proposal; the value of the second statement above is list1.addAll( list3 ). Different than the builder proposal; the intermediate values, e.g. list1.addAll( list2 ), are always discarded.

    Stephen Colebourne has suggested something similar but proposed .do. instead of -> and didn’t include the original argument getting passed to all the methods, i.e in the second example above list1 is given to both addAlls.

  38. Howard Lovatt Says:

    Re Traits and Mixins

    Nothing greatly against mixins, I prefer the flat nature of traits and the more explicit conflict resolution. Mixins would essentially be the same in Java, they could even have the same syntax, the only difference would be that class XY implements X,Y {} would automatically get a Y.foo since Y was mixed in last. Either would be good :)

    Where does the proposed syntax break old code? Isn’t everything proposed currently a syntax error? What have I missed?

    The implementation technique proposed for traits (class loader adds methods) could be used to allow the user to add methods also (Josh Bloch’s point that it would be nice if the user of an API could add methods). EG:

    extension MyList extends List {
    sort() { …. };
    }

    Then in the main class (or at least before List is used):

    import MyList; // Not only tells the compiler to use MyList in the file but also extends List at runtime - file that imports MyList must be loaded before a file that uses List - OK to multiply import MyList

  39. Mark Mahieu Says:

    Peter,

    Wasn’t sure whether to post this on your blog or Neal’s, but anyway:

    I’ve been playing around with implementations of methods like curry() with the closures prototype, and have been wondering how best to deal with a couple of issues, namely:
    1) I need a different implementation of curry() for n argument functions to the implementation I need for n+1 argument functions.
    2) For each of these variations, I’d also want versions which work with primitive types as the arguments and/or result value. Off the top of my head, I think this leads me to something like (9 to the power of (number of arguments + 1)) implementations of curry() for each number of arguments I want to cover. Ouch.

    There are a handful of other similar ‘building block’ methods with the same issues. Writing all these implementations isn’t particularly hard - I can write something else to generate them up to some arbitrary number of arguments, and I’ve been implementing them as static methods in a ‘utility’ class, ready for import static usage, but the above issues lead to some practical concerns regarding byte-code size, and usability with code completion features in IDEs.

    Ideally I’d want curry() and friends to appear to be instance methods on a function type, but obviously they can’t really be instance methods since function types are defined in terms of single-method interfaces.

    Use-site extension methods get around that and make using them a little easier, but solve none of the practical issues.

    It occurred to me that declaration site extension methods might offer a way though - the closures spec could conceivably define a handful of extension methods on each function type interface, for example javax.lang.function.OIO might look like:

    public interface OIO { // system-generated

    R invoke(int x1, A2 x2) throws E;

    {int => {A2 => R}} curry() import static javax.lang.function.OIO.Extensions.curry;

    protected static class Extensions {
    static {int => {A2 => R throws E}} curry({int, A2 => R throws E} fn) {
    return {int x1 => {A2 x2 => fn.invoke(x1, x2)}};
    }
    }
    }

    I’m not sure how nicely this plays with marker interfaces (such as RestrictedFunction), and the class Extensions should really be private to prevent the static curry method from ‘leaking’ into a closure literal’s scope (Java 6 doesn’t like import static from a private static inner class, for reasons I’m not sure of) - but maybe there’s mileage in this; if these interfaces are to be generated by the VM at run-time (I believe that’s the intention), then we only get as many implementations of curry (or whatever) as are needed, solving the practical issues in a stroke.

    Of course the underlying implementation could be different from the above, as long as the function type interfaces can be described in terms of the standard language feature-set.

    Mark

  40. Peter Ahé Says:

    Howard,

    Traits and Mixins are not the same. Mixins do not allow multiple inheritance (although they provide the same level of code sharing as with multiple inheritance).

    I’m not saying that your proposed syntax breaks existing programs. The motivation for both kinds of extension methods is to mediate the fact that you cannot add a method to an interface without breaking source compatibility. Replay your example in this order:

    1. Declare interface X without any methods.
    2. Declare interface Y without any methods.
    3. Declare class XY without any methods.

    Now, lets say you want to add a method m to interface X. Then XY would fail to compile. Your solution is to use traits. Ignoring that we need to change the JVM so it copies method m from X to XY at load time (and work out some rules– which I’m not sure would not have other compatibility problems– for how the JVM does so), it solves the compatibility issue for now.

    Then add method m to Y. Now XY fails to compile (which was the entire point of your example). This means that traits does not solve the problem of compatibly adding a method to an interface.

    There is a similar problem with declaration-site extension methods. I believe this can be controlled by issuing compile-time warnings and having a tie-break rule. However, I’m seriously beginning to doubt this would be worth the hassle.

    The lesson to learn is that there is no such thing as simple language extension to Java.

  41. Howard Lovatt Says:

    Peter,

    Sure, start off with:

    interface X {}
    interface Y {}
    class XY implements X, Y {}

    Then change both X and Y to:

    interface X { int m() { return 1; } }
    interface Y { int m() { return 2; } }

    And XY won’t compile. But I think that is the behaviour you want. The feature allows you to add methods but within limits. And the limits are found by the compiler (or loader) and so you still retain static typing. Problems happen with other proposals, e.g. use-site:

    import static XExtension; // XExtension defines m
    import static YExtension; // YExtension also defines m

    X xy1 = new XY();
    Y xy2 = new XY();
    XY xy3 = new XY();
    xy1.m(); // calls X.m
    xy2.m(); // calls Y.m
    xy3.m(); // Error

    Very confusing! They are all XYs after all! Not at all OO!

    You can still compile XY, without an error, and a previously compiled XY will still run. Yes this is better from a compatibility point of view, but I think the problems outweigh the advantages.

    Declaration-site has the same problems as use-site, just different syntax (which does have advantages - but I am discussing method resolution). Scala style Mixins are very similar to Traits, except that the method to call in the case of a conflict is automatically resolved. So going back to your original example, when m is added to both X and Y using a Mixin:

    class XY implements X, Y {}

    Is still OK. The class loader adds Y.m to XY since Y is mixed in after X. This would give you the source compatibility you want, but I think an error is better (it will be a rare error and easily resolved and has the great advantage of clarity).

    Cheers,

    Howard.

  42. Howard Lovatt Says:

    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(); };

  43. Axel Groß Says:

    Hi Peter!

    Hmm… maybe your approach was still too far reaching to be a simple change. Maybe making it even simpler would help:

    I still think declaration site extensions could have its uses, if you completely forget about having some kind of inheritance available.

    This would mean those methods are just available if an object is used through that specific interface/type declaration and thus could not have any collisions with implementing/extending types.

    package java.util;
    interface List … { …
    void sort() import static java.util.Collections.sort; …
    }
    interface Sortable … {
    void sort() import static my.Helper.sort; …
    }

    class Evil2 implements Sortable, List … { … }
    class Evil3 extends Evil2 {
    void sort(){ … } …
    }
    List l = new Evil3();
    l.sort(); // == Collections.sort(l);
    ((Sortable)l).sort(); // == Helper.sort(l);
    ((Evil3)l).sort(); // == Evil3#sort();
    ((Evil2)l).sort(); // COMPILE ERROR - Evil2#sort() doesnt exist;

    If you wanted to ‘inherit’ the extension methods you would have to declare it by hand in inheriting interfaces (but if you want inheritance you should have made it part of the interface anyway ;) ).
    This also could help in declaring functionality which should not be inherited.
    So (bad) e.g. you could have a sort method for a general List but not for a sorted list.

    package java.util;
    interface List … { …
    ListIsSorted sort() import static at.mydomain.Collections.sort; …
    }
    interface ListIsSorted extends List {
    //no sort method at all …
    }

    List l = new ListImpl();
    ListIsSorted lSorted = l.sort(); // == at.mydomain.Collections.sort(l);
    // sort method is not needed for a list already sorted
    lSorted.sort(); // COMPILE ERROR - interface SortedList has no method ’sort’; But supertype List has it as extension method.

    I think this feature would be useful _and_ a simple change.

  44. Discussions on Java7 new features « mindstorms Says:

    […] Declaration-Site Extension Methods […]

Leave a Reply