Cross compilation and default methods

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Apr 4 09:10:50 PDT 2013


On 04/04/13 16:43, Stephan Herrmann wrote:
> Hi Maurizio,
>
> On 04/03/2013 10:43 AM, Maurizio Cimadamore wrote:
>> the current status quo is:
>>
>> 1) javac reads default methods, regardless of the source/target versions
>> used to compile
>> 2) a class is allowed to implement an interface and _not_ providing
>> implementations for the defaults, regardless of source/target
>> 3) default method resolution only kicks in when source = 8 (mainly for
>> perfomance/compatibility risks)
>> 4) well-formedness checks on defaults (i.e. clashes) are only enabled if
>> source = 8
>
> Thanks.
> Unfortunately, I don't see how this explains the following observation:
>
> compile this at -source 1.8:
>
>     interface I0 {
>       void foo();
>     }
>     public interface I extends I0 {
>       default void foo() { }
>       default void bar() { }
>     }
>
> then compile this at -source 1.7:
>
>     public class C implements I {
>       void test() {
>         foo();
>         bar();
>         I i = this;
>         i.foo();
>         i.bar();
>       }
>     }
>
> I get 3 errors:

It might be a problem with that particular hierarchy; the following 
works ok:

//compiled with JDK 8
interface I {
default void m() {}
}

//compiled with JDK 7
class E implements I { }

>
> C.java:1: error: C is not abstract and does not override abstract 
> method foo() in I0
> public class C implements I {
>        ^
> C.java:3: error: cannot find symbol
>     foo();
>     ^
>   symbol:   method foo()
>   location: class C
> C.java:4: error: cannot find symbol
>     bar();
>     ^
>   symbol:   method bar()
>   location: class C
>
> Sorry, if I'm being dense.
> I can see that I.foo() is not recognized as implementing I0.foo(), OK.
> That situation should probably just be avoided by library designers
> to avoid confusion.
>
> But why can those methods be invoked via 'i' but not via implicit
> 'this'? Is this an implementation detail leaking out into observable
> behavior? How can this be explained to users?
This is a result of the JDK 7 invariant on class well-formedness. If a 
class is well-formed, a class should contain all required concrete 
methods implementing corresponding abstract methods in implemented 
interfaces. This means that javac doesn't even bother looking into 
interfaces when resolving a method call where the receiver is a concrete 
class.

Maurizio
>
>
>> I believe this is an area where there's room for improvement; things
>> like (3) seems to be counterintuitive given that the compiler knows
>> about default methods. What has put me off to go ahead and support
>> default method resolution with source < 8 is the fact that the new
>> resolution algorithm needs to look at more supertypes than the old one
>> (i.e. it needs to look at all supertinterface before being able to give
>> up). This leads to subtle problems where you need more dependencies on
>> your classpath in order to be able to compile a class, as a seemingly
>> unrelated interface that was not needed before will suddenly be
>> inspected by javac.
>
> I can see. I don't think users will actually expect full fledged
> analysis of default methods in 1.7 mode. Not being blamed about
> unimplemented default methods is already good. There has to be a line
> beyond which compilation in 1.7 against 1.8 class files tells the
> user: sorry, I can't figure this out, please align compiler settings
> and versions of class libraries. My main question is: where exactly
> will you draw this line? I'd love to see javac and Eclipse drawing
> the same line, so can we make this explicit?
> From there, each compiler team can figure out how to explain the
> situation to the user.
>
> cheers,
> Stephan
>
>



More information about the lambda-spec-observers mailing list