Bug 321706 - Cannot override method to avoid name clash error if sub-class method generic extends class
Summary: Cannot override method to avoid name clash error if sub-class method generic ...
Status: VERIFIED INVALID
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: PC Linux
: P3 major (vote)
Target Milestone: 3.7 M2   Edit
Assignee: Srikanth Sankaran CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-04 08:31 EDT by Tobias Brennecke CLA
Modified: 2010-09-14 10:02 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Brennecke CLA 2010-08-04 08:31:16 EDT
Build Identifier: 20100617-1415

If overriding a method which returns a generic T with a method returning "T extends SomeClass", a name clash is caused and it is suggested to @Override this method, but this is not possible because the method signatures do not match.
This makes the code uncompilable, although if "ereasing" the types, the method should be overrideable.
If the return type matches (deleting extends), everything is fine again.


This issue is blocking a LOT of my work for now so I'd have to go back to eclipse 3.5 :(
This bug is really serious in my eyes, as I'm surely not the only one who is affected.

OS is kubuntu lucid.
java -version shows

java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)

Setting the JRE compatibility to 1.5 did not help

Reproducible: Always

Steps to Reproduce:
1. Create these three test classes:

public class MyType {
}

public class MyBaseClass {
  public <T> T myMethod() {
    return null;
  }
}

public class Extender extends MyBaseClass{

  //Name clash, but cannot override
  public <T extends MyType> T myMethod() {
    return null;
  }
}

2. Now an error "Name clash: The method myMethod() of type Extender has the same erasure as myMethod() of type MyBaseClass but does not override it"
3. Try avoiding the name clash error by adding an @Override annotation to Extender.myMethod()
This causes the following error: "The method myMethod() of type Extender must override or implement a supertype method".
4. Code is uncompilable
Comment 1 Ayushman Jain CLA 2010-08-04 09:31:44 EDT
(In reply to comment #0)
> Build Identifier: 20100617-1415
> 
> If overriding a method which returns a generic T with a method returning "T
> extends SomeClass", a name clash is caused and it is suggested to @Override
> this method, but this is not possible because the method signatures do not
> match.
> This makes the code uncompilable, although if "ereasing" the types, the method
> should be overrideable.
> If the return type matches (deleting extends), everything is fine again.
> 

This is a consequence of a bug in java 6 which has been fixed in jdk 7. Compiling the given test classes with java6 gives no errors, but doing so with jdk7 gives the same name clash error, which is valid since the erasure of both methods is the same (see bug 317586). So given that the name clash error is correct, we need to make sure that adding @Override annotation doesn't cause grief.
Srikanth, what do you think?
Comment 2 Srikanth Sankaran CLA 2010-08-04 11:25:07 EDT
(In reply to comment #1)
> (In reply to comment #0)
> > Build Identifier: 20100617-1415
> > 
> > If overriding a method which returns a generic T with a method returning "T
> > extends SomeClass", a name clash is caused and it is suggested to @Override
> > this method, but this is not possible because the method signatures do not
> > match.
> > This makes the code uncompilable, although if "ereasing" the types, the method
> > should be overrideable.
> > If the return type matches (deleting extends), everything is fine again.
> > 
> 
> This is a consequence of a bug in java 6 which has been fixed in jdk 7.
> Compiling the given test classes with java6 gives no errors, but doing so with
> jdk7 gives the same name clash error, which is valid since the erasure of both
> methods is the same (see bug 317586). So given that the name clash error is
> correct, we need to make sure that adding @Override annotation doesn't cause
> grief.
> Srikanth, what do you think?

bug 317586 is about there not being a most specific method for an invocation
while this is about a name clash, so they are not connected. This needs further
analysis and I'll follow up on this.
Comment 3 Stephan Herrmann CLA 2010-08-04 16:56:18 EDT
(In reply to comment #0)

Stupid question: how do you implement such a method other than "return null"...

> public class MyBaseClass {
>   public <T> T myMethod() {
>     return null;
>   }
> }

.. given that a client can say 
  MyBaseClass mbc = new MyBaseClass();
  Foo f = mbc.myMethod();

for any type Foo that is unknown to myMethod.
That method must be truely magic!
 
> public class Extender extends MyBaseClass{
> 
>   //Name clash, but cannot override
>   public <T extends MyType> T myMethod() {
>     return null;
>   }
> }

If you have some implementation for MyBaseClass.myMethod, consider
this client:
  MyBaseClass mbc = new Extender();
  Foo f = mbc.myMethod();

this Client certainly is correct, but if myMethod is actually overridden
that would mean that Extender.myMethod must return a type that's both
a subclass of MyType and also compatible to Foo, which may not exist.
Those are just incompatible guarantees.
So where should this type error be reported?

And again: what's the use: there is no part in the code that can make
use of the "extends MyType" part: within myMethod an upper bound for
the return type is useless and the client of MyBaseClass has already
a guarantee that *any* type is valid for T.

> 4. Code is uncompilable

At first look this seems the exact right thing to me.

Am I missing anything?
Comment 4 Tobias Brennecke CLA 2010-08-05 05:57:06 EDT
I'm sorry I missed out the Class<T> c as parameter for the myParam method and the returns were some replacements, too. I only wanted to keep the example as short as possible...

I did some testing together with my boss(using javac and javap), the reasons why this correctly does not work are not obvious on the first glance.
The compiler does not "see" the generics, so the code does compile(to it myMethod is overridden) but the runtime sees that it's not the same T in myBaseClass and Extender, so in effect, myMethod cannot be overridden and the name clash error is correct, too.

I think you can safely close this ticket and sorry for wasting your time :)

(In reply to comment #3)
> (In reply to comment #0)
> 
> Stupid question: how do you implement such a method other than "return null"...
> 
> > public class MyBaseClass {
> >   public <T> T myMethod() {
> >     return null;
> >   }
> > }
> 
> .. given that a client can say 
>   MyBaseClass mbc = new MyBaseClass();
>   Foo f = mbc.myMethod();
> 
> for any type Foo that is unknown to myMethod.
> That method must be truely magic!
> 
> > public class Extender extends MyBaseClass{
> > 
> >   //Name clash, but cannot override
> >   public <T extends MyType> T myMethod() {
> >     return null;
> >   }
> > }
> 
> If you have some implementation for MyBaseClass.myMethod, consider
> this client:
>   MyBaseClass mbc = new Extender();
>   Foo f = mbc.myMethod();
> 
> this Client certainly is correct, but if myMethod is actually overridden
> that would mean that Extender.myMethod must return a type that's both
> a subclass of MyType and also compatible to Foo, which may not exist.
> Those are just incompatible guarantees.
> So where should this type error be reported?
> 
> And again: what's the use: there is no part in the code that can make
> use of the "extends MyType" part: within myMethod an upper bound for
> the return type is useless and the client of MyBaseClass has already
> a guarantee that *any* type is valid for T.
> 
> > 4. Code is uncompilable
> 
> At first look this seems the exact right thing to me.
> 
> Am I missing anything?
Comment 5 Srikanth Sankaran CLA 2010-08-05 06:54:17 EDT
(In reply to comment #4)

> I think you can safely close this ticket and sorry for wasting your time :)

OK, Thanks for the clarification Tobias.

(In reply to comment #0)
> 3. Try avoiding the name clash error by adding an @Override annotation to
> Extender.myMethod()
> This causes the following error: "The method myMethod() of type Extender must
> override or implement a supertype method".

You cannot avoid the name clash error this way i.e by adding @Override
annotation. This annotation informs the compiler of your intent to override,
but has no influence on whether the method actually does override or not.

(In reply to comment #3)
> (In reply to comment #0)
> 
> Stupid question: how do you implement such a method other than "return null"...

[...]

> .. given that a client can say 
>   MyBaseClass mbc = new MyBaseClass();
>   Foo f = mbc.myMethod();
> 
> for any type Foo that is unknown to myMethod.
> That method must be truely magic!

Yes,

> If you have some implementation for MyBaseClass.myMethod, consider
> this client:
>   MyBaseClass mbc = new Extender();
>   Foo f = mbc.myMethod();
> 
> this Client certainly is correct, but if myMethod is actually overridden
> that would mean that Extender.myMethod must return a type that's both
> a subclass of MyType and also compatible to Foo, which may not exist.
> Those are just incompatible guarantees.
> So where should this type error be reported?

Yes,

> And again: what's the use: there is no part in the code that can make
> use of the "extends MyType" part: within myMethod an upper bound for
> the return type is useless and the client of MyBaseClass has already
> a guarantee that *any* type is valid for T.
> 
> > 4. Code is uncompilable
> 
> At first look this seems the exact right thing to me.

Yes.

All that being said, I was looking up the JLS in order to cite
chapter and verse why this code should not compile: Though both
javac7 and eclipse claim the methods are not override equivalent,
I couldn't quite locate the spec after an initial read that would
make it illegal.

JLS3 8.4.2 bullet with wording:

Let <A1,...,An> be the formal type parameters of M and let <B1,...,Bn> be
the formal type parameters of N. After renaming each occurrence of a Bi in Nā€™s
type to Ai the bounds of corresponding type variables and the argument types
of M and N are the same.

establishes that the two methods DON'T have the same signature.

However the second bullet in the definition of subsignature (same section)
viz: 

... the signature of m1 is the same as the erasure of the signature of m2.

still would hold and would appear to make them override-equivalent. It does
feel like a hole in the spec though.

However since eclipse behavior matches javac latest behavior, I'll leave
the matter there and close this as INVALID.

See also:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=107105
Comment 6 Stephan Herrmann CLA 2010-08-05 18:20:00 EDT
(In reply to comment #5)
> [...]
> However the second bullet in the definition of subsignature (same section)
> viz: 
> 
> ... the signature of m1 is the same as the erasure of the signature of m2.
> 
> still would hold and would appear to make them override-equivalent. It does
> feel like a hole in the spec though.

Wait: this rule doesn't allow you to erase *both* signature for comparison,
the erasure of one signature must be identical to the exact signature of
the other.
 
This is the special rule for compatibility of non-generified code, but once you
have generics in both methods the other rule you quoted applies and we're good.
Comment 7 Srikanth Sankaran CLA 2010-08-05 22:26:02 EDT
(In reply to comment #6)

> Wait: this rule doesn't allow you to erase *both* signature for comparison,
> the erasure of one signature must be identical to the exact signature of
> the other.

Yes, but section 8.4.2 only defines Signature indirectly in terms of
when two methods are considered to have the same signature. It does
not say what is the influence of the type variable on the method
signature in a case where the method arguments don't make use of the
type variables ?

> This is the special rule for compatibility of non-generified code, but once you
> have generics in both methods the other rule you quoted applies and we're good.

That requires a leap not explicitly allowed by 8.4.2. No ? 

As commented earlier, I agree with your interpretation and conclusion and
merely pointing out that the wording doesn't quite disallow the second
subsignature criterion.
Comment 8 Olivier Thomann CLA 2010-09-14 10:02:39 EDT
Verified for 3.7M2.