Uncertainty about fix for JDK-5059679
Alex Buckley
alex.buckley at oracle.com
Mon Feb 13 21:15:49 UTC 2023
On 2/13/2023 10:28 AM, Archie Cobbs wrote:
> public class NarrowingNameClash2 {
>
> public abstract class Upper<T> {
> abstract void method(T param);
> }
>
> public abstract class Lower<R> extends Upper<Class<R>> {
> abstract void method(Class<?> param); // name clash here???
> }
> }
The core of all this is that method(Class<?>) in Lower<R> is not a
subsignature of method(Class<R>) in Upper<Class<R>>.
This means that Lower<R> inherits method(Class<R>) from its direct
superclass type Upper<Class<R>>. (See 8.4.8)
It's dangerous for Lower<R> to have method(Class<R>) and
method(Class<?>) at the same time.
8.4.8.3 detects the problem.
The simple way to apply 8.4.8.3 is to set C = Lower and A = Upper, so
that m1 = method(Class<?>) and m2 = method(Class<R>).
As you say, a compile-time error is due.
> Side note/question: Presumably when Upper.method(T) is inherited by
> Lower, its type changes from void method(T) to void method(Class<R>) -
> correct? Is this actually stated anywhere?
8.2 says:
The members of a class are all of the following:
- Members inherited from its direct superclass type (§8.1.4) ...
The terminology of "class" versus "direct superclass type" is precise
and deliberate. The members of the (generic) class Lower<R> include the
members inherited from the direct superclass type of Lower<R>, which is
Upper<Class<R>>. To be clear: Lower<R> is a (generic) class,
Upper<Class<R>> is a (parameterized) type. The members inherited from
Upper<Class<R>> will have R in their own signatures, not T.
If you added a flag to make javac enumerate the members of every generic
class and every parameterized type seen in the program, it would be very
useful.
> Now consider the same thing except using interfaces:
>
> public class NarrowingNameClash {
>
> public interface Upper<T> {
> void method(T param);
> }
>
> public interface Lower<R> extends Upper<Class<R>> {
> void method(Class<?> param); // name clash here?
> }
> }
>
> According to my reading, interfaces do NOT inherit methods from
> superinterfaces.
You might be thinking about the private methods and static methods of an
interface, which are indeed not inherited by a subinterface. Abstract
methods in an interface have always been inherited by a subinterface
(see 9.1.3), unless of course they are overridden (see 9.2).
The interface Lower<R> inherits method(Class<R>) from its direct
superinterface type Upper<Class<R>>. (See 9.4.1)
No overriding occurs in 9.4.1.1, so 9.4.1.2 has no requirements.
It's OK for Lower<R> to have method(Class<R>) and method(Class<?>) at
the same time. 9.4.2 describes the situation. The methods are not
override-equivalent. No compile-time error is due.
A class can implement Lower<SomeType> by declaring a concrete method
`public void method(Class p)`. Whether an interface should allow more
overloading of members than a class is a design discussion that I do not
propose to revisit today.
Alex
More information about the compiler-dev
mailing list