PRE-PROPOSAL: Extension methods
Xavi Miró
xmirog at gmail.com
Wed Mar 18 23:46:15 PDT 2009
I like this feature a lot. My only concern was what happens when a new
method is added to a class that has been extended with an extension
method, but now I think this could be easily solved with a compiler
warning when an imported extension method has the same signature as a
method of the class or interface it extends. I mean that if you write a
code like this when the class SomeClass class doesn't have a method sort
(I'm not using interfaces now because the problem is easier to appear
with classes):
import static some.package.SomeClass.sort;
SomeClass myObj = ...
myObj.sort(); // uses SomeClass.sort extension method
...and some time later you use a new version of SomeClass which has the
sort method with the same signature, the same source code could behave
differently:
import static some.package.SomeClass.sort;
SomeClass myObj = ...
myObj.sort(); // uses SomeClass.sort instance method
I think that, if the compiler writes a warning like "The extension
method SomeClass.sort is not used because there is a sort method in the
class SomeClass", then the problem is gone, because you can do three
different things:
1) Remove the extension method import and leave the call as is if you
have checked that the behaviour of the new method sort is the same as
the extension method's.
2) Remove the extension method import and rewrite the sort method call
as a normal static class call if you have seen a different behaviour in
the new sort method.
3) Leave the extension method import and write an annotation to suppress
the warning if you have checked the behaviour is the same in both
methods and you want your source code compatible with both versions of
the class SomeClass (the extension method will be used with the old
version, and the instance method with the new version).
I think the warning message would allow the programmer to decide what
to do and to be aware of possible behaviour changes that could be
difficult to track when upgrading to a new version of an extended class.
Regards,
Xavi
Neal Gafter escribió:
> On Tue, Mar 17, 2009 at 11:56 PM, Kevin Krouse <kevin.krouse at gmail.com> wrote:
>
>> I'm interested in extension methods.
>>
>
> I'll write up a full proposal if I have any indication it's something
> Joe/Sun(/IBM) would consider for project Coin. The basic idea would
> work like this:
>
> Within a static method, you can use "this" as an new qualifier on the
> first method parameter, which must be a reference type. This would be
> reflected in the class file format as either a new flag, or a new
> classfile attribute ("ExtensionMethod") on the method.
>
> When an extension method has been statically imported, you can use it
> as if it is a member of the type of its first argument. The name
> lookup rules for a method invocation
>
> o.f(...)
>
> are augmented as follows. When identifying candidates for overload
> resolution, if no accessible candidates of the correct name are found
> as a member of the static type of the receiver (JLS 15.12.1 and
> 15.12.2), then we consider as candidates those statically imported
> methods with name f, and perform the overload resolution among them as
> if the invocation had been written
>
> f(o, ...)
>
> This is backward compatible, as it assigns meanings to expressions
> that were previously errors, and does not change the meaning of code
> that was not previously an error.
>
> There are a number of benefits to this approach. A large number of
> static utility class members can and probably should be retrofitted to
> use extension methods, making it possible to use a much more
> convenient syntax for common operations.
>
> import static java.util.Collections.sort;
> List<Integer> list = ...
> list.sort(); // uses Collections.sort extension method
>
> Similarly, it allows extension methods to operate on arrays
>
> import static java.util.Arrays.sort;
> String[] strings = ...
> strings.sort(); // uses Arrays.sort extension method
>
> The syntactic convenience of this is greater (i.e. code becomes more
> readable) when multiple invocations work together in an expression.
>
> One of the more important benefits of this approach is that it enables
> future language changes to be defined by syntactic translation, while
> allowing more flexible retrofitting of those language changes onto
> existing APIs than would be possible without extension methods. For
> example, one could define an ARM construct by translation of something
> like
>
> protected (expression) statement
>
> into
>
> {
> Type1 $t1 = expression
> Type2 $t2 = $t1.protectedStart();
> try {
> statement
> } finally {
> $t2.protectedEnd();
> }
> }
>
> (with appropriate inversion of suppressed exceptions, if you please).
>
> Then, to add support for this new ARM construct to some particular API
> you would either add these methods to the API or define extension
> methods. If done using extension methods or final instance methods,
> they are likely to be inlined by HotSpot if used in frequently
> executed code, so the performance overhead is vanishingly small.
> Since extension methods can be added even to existing interfaces
> without breaking compatibility, such an ARM construct could be
> retrofitted onto many more APIs than the currently proposed construct.
> It could easily be retrofitted onto java.util.concurrent.locks.Lock,
> for example.
>
> See also http://www.javac.info/ExtensionMethods.html
>
>
>
More information about the coin-dev
mailing list