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