Defaut methods are not visible if -source 1.7 is set
Dan Smith
daniel.smith at oracle.com
Tue Nov 26 16:35:42 PST 2013
I finally had a chance to dig a little deeper into what's actually happening here. It's a narrower problem than I expected.
javac does a lot of work to ensure that, under -source 7, default methods are "visible" at appropriate times, but don't get in the way:
- You can @Override the method from any subtype
- You never have to implement the method in a subtype
- You can invoke the method as a member of the interface, or a subinterface, or an implementing abstract class
The only exception is that you can't invoke the method as a member of a concrete class:
interface I { default void m() {} }
interface J extends I {}
abstract class A implements I {}
class B implements I {}
// compile with -source 7:
class Test {
public static void test(I i, J j, A a, B b) {
i.m(); // ok
j.m(); // ok
a.m(); // ok
b.m(); // error
}
}
So this looks much less like a design decision and much more like an overlooked corner case. I've created a bug:
https://bugs.openjdk.java.net/browse/JDK-8029240
I expect this will likely be addressed in an update release of Java 8.
—Dan
On Nov 1, 2013, at 8:59 AM, Stephan Herrmann <stephan.herrmann at berlin.de> wrote:
> In terms of coordinating the behavior of javac and the Eclipse compiler
> I'm happy this issue has been raised here.
> I couldn't see any real conclusion, yet. Did I miss a relevant post?
> How do you think a compiler at -source 1.7 *should* handle default methods?
>
> Here's another example from an earlier instance of this discussion:
>
> Compile at -source 1.8:
>
> public interface I {
> default void foo() {}
> }
>
> and consuming the .class of the above compile at -source 1.7:
>
> public class CI implements I {
> void test(I i) {
> this.foo();
> i.foo();
> }
> }
>
> From two calls to the same method, javac (all versions) flags one:
>
> CI.java:3: error: cannot find symbol
> this.foo();
> ^
> symbol: method foo()
> 1 error
>
> Will this be the final behavior of javac?
>
> For comparison, the Eclipse compiler (beta) currently reports only this:
>
> public class CI implements I {
> ^^
> The type CI must implement the inherited abstract method I.foo()
> ----------
> 1 problem (1 error)
>
> Whereas the latest release version reports nothing.
>
> Stephan
>
>
> On 10/29/2013 06:26 PM, Remi Forax wrote:
>> This is from enhanced-metadata-spec-discuss mailing list
>> but I think this issue can interest this audience because it seems
>> that javac doesn't respect the spec we have drafted or the spec has changed without me noticing it.
>> Anyway there is a discrepancy somewhere.
>>
>> From Joe Darcy:
>>
>>>> Wouldn't this risk the same issues as when we turned isAnnotationPresent() into a default?
>>>>
>>>>
>>>
>>> No; we don't have the same hazard here as with isAnnotationPresent. The issue we ran into with making isAnnotationPresent a
>>> default method was that isAnnotationPresent was part of the original AnnotatedElement interface defined way back in Java SE 5. In
>>> implementation decision in javac did not expose the existence of default methods to code being compiled under source levels less
>>> than 8. That is a pragmatic choice and usually gives the desired result, but not in this case.
>>>
>>
>> So it seems that javac 8 doesn't see default methods if source level is 1.7 (-source 1.7)
>> and as Joe notice this hamper to transform any existing abstract method to a default method.
>>
>> I'm pretty sure that we have talked about that and said that adding default to a method should be
>> source compatible when we have discussed about Iterator.remove.
>> Otherwise it goes against the intuition that providing a body to an existing abstract method is harmless.
>>
>> So either javac8 implementation is not correct (BTW, javac7 see default methods)
>> or the spec shoud be changed to say that adding a default implementation is not a compatible change
>> and Iterator.remove should be re-abstracted.
>>
>> regards,
>> Rémi
>>
>
More information about the lambda-spec-experts
mailing list