Extension method and covariant return type

Alex Buckley alex.buckley at oracle.com
Thu Jun 3 19:00:50 PDT 2010


Hi Remi,

Clever stuff. It took me a while to swap in bridge methods for 
overriding with covariant return type. Let's clarify that this problem 
is about two kinds of bridge method:

1) the bridge method mentioned in Brian's doc, section 6, that 
dispatches through some yet-to-be-determined mechanism to the default 
method. Call this a Brian-bridge.

2) the bridge method inserted to ensure invokeinterface on the supertype 
resolves successfully when the receiver is a subtype whose source had a 
covariant return. Call this a Remi-bridge.

A correct implementation must indeed add the necessary Remi-bridges for 
each Brian-bridge, via whatever mechanism is used for the Brian-bridge 
itself. (Multiple Remi-bridges may be required for each Brian-bridge if 
a subinterface's defender method overrides multiple superinterfaces' 
defender methods with a return that's covariant to all of them.)

But the Remi-bridges are implementation details, like all bridge 
methods. Whatever the Java Language Spec says about the syntax and 
semantics of defender methods, the compilation of such methods to 
Brian-bridges and Remi-bridges will not be specified. The Java VM Spec 
may well define new ClassFile artifacts in support of Brian-bridges, but 
they won't be explicit supersets of corresponding JLS artifacts.

Alex

On 5/17/2010 1:28 AM, Rémi Forax wrote:
> I think there is something which is not specified: how covariant return type
> (and generics) interacts with the extension method.
> 
> Suppose I have something like that:
> 
> public interface Iterable<E> {
>    extension <F> Iterable<F> map(F(E) lambda)
>      default Collections.<E, F>iterableMap(F(E));
> }
> 
> public interface Collection<E> implements Iterable<E> {
>    extension <F> Collection<F> map(F(E) lambda)
>      default Collections.<E, F>collectionMap(F(E));
> }
> 
> Currently when method that aren't defender method,
> the compiler adds a bridge (ACC_BRIDGE) method
> to all classes that implements the interfaces
> to do the bridge between the methods.
> 
> Because defender methods can be inserted at runtime,
> the compiler can not add this bridge
> (the class can be compiler with a non 1.7 compiler).
> But the compiler can add another defender method that will do the bridge:
> 
> public interface Collection<E> implements Iterable<E> {
>    extension <F> Collection<F> map(F(E) lambda)
>      default Collections.<E, F>collectionMap(F(E));
> 
>    extension <F> Iterable<F> map(F(E) lambda)
>      default (Collection<F>)Collection<E>.map(F(E)); // brige inserted 
> by the compiler
> }
> 
> This means that the spec must be changed a little to allow to
> reference method that aren't static and with a slighty different signature
> (bridge can require to cast parameter).
> Note that because defender bridges are only added by the compiler,
> the Java spec can only authorize static default but the JVM spec
> must authorize reference to virtual method + casts
> (Hotspot already have call stubs to insert casts without requiring a 
> full stack frame).
> 
> A question remains, should declaration of extension method allowed in class
> (not only in interface) to retrofit standard bridge mecanism to always
> use defender bridge.
> 
> Rémi


More information about the lambda-dev mailing list