Bug 99453 - [1.5] cannot invoke generic methods inferred by supertype
Summary: [1.5] cannot invoke generic methods inferred by supertype
Status: RESOLVED INVALID
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.1 RC4   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-06-10 15:48 EDT by Matthew Hall CLA
Modified: 2005-06-20 13:09 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthew Hall CLA 2005-06-10 15:48:22 EDT
I have developed my own Cloneable interface to take advantage of generics.

  /** A more useful Cloneable interface using generics. */
  public interface Cloneable<T extends Cloneable<T>> {
    public T clone();
  }

I also have a Map interface called ClonableMap, to make it more convenient to 
create deep copies of maps.  The same idea could be used for making deep 
copies of the other Collection interfaces.

  /** Interface for a clonable map. */
  public interface CloneableMap<K, V extends Cloneable<V>>
  extends Map<K, V>, Cloneable<CloneableMap<K, V>> {}

  /** TreeMap implementation of CloneableMap. */
  public class CloneableTreeMap<K, V extends Cloneable<V>>
  extends TreeMap<K, V> implements CloneableMap<K, V> {
    public CloneableTreeMap() {}

    public CloneableTreeMap(CloneableMap<K, V> map) {
      super(map);
      for (Map.Entry<K, V> entry : entrySet())
        entry.setValue(entry.getValue().clone());
    }

    public CloneableMap<K, V> clone() {
      return new CloneableTreeMap<K, V>(this);
    }
  }

So far, so good.  The problem I'm running into is that if I define a generic 
interface that extends Cloneable<T>:

  public interface C<T extends C<T>> implements Cloneable<T> {}

And then add a few concrete implementation classes:

  public class D implements C<D> {
    public D clone() { return new D(); }
  }

  public class E implements C<E> {
    public E clone() { return new E(); }
  }

Based on this structure there seems to be no way to create a CloneableMap<Key, 
C<?>>.

  CloneableMap<String, C<?>> map = new CloneableTreeMap<String, C<?>>();
                       ^
  map.put("first", new D());
  map.put("second", new E());

Changing the generic type from C<?> to raw type C does not help.

Maybe I'm looking at this the wrong way, but since C<T extends C<T>> extends 
Cloneable<T>, with T bounded to implement C<T>, doesn't that guarantee that C<?
> must at a minimum implement Cloneable<C<?>>?  My compiler doesn't think so:

	Bound mismatch: The type C is not a valid substitute for the bounded 
parameter <V extends Cloneable<V>> of the type CloneableMap<K,V>

So far the only way I have found to overcome this is to change the interface 
so it directly implements Cloneable for that interface, and have each 
implementing class directly implement Cloneable for the concrete type:

  public interface C implements Cloneable<C> {}

  public class D implements C, Cloneable<D> {
    public D clone() { return new D(); }
  }

  public class E implements C, Cloneable<E> {
    public E clone() { return new E(); }
  }

This gets me the functionality I need but I am quite confused about why the 
first case will not compile.
Comment 1 Matthew Hall CLA 2005-06-10 16:01:38 EDT
javac complains if you re-implement the Cloneable<T> interface in the concrete 
class.  The new lowest common denominator is that you can refine the return 
type but not implement the Cloneable<T> interface for the concrete class:

  public interface C implements Cloneable<C> {}

  public class D implements C {
    public D clone() { return new D(); }
  }

  public class E implements C {
    public E clone() { return new E(); }
  }
Comment 2 Philipe Mulet CLA 2005-06-20 10:44:45 EDT
CloneableMap< ..., C<?>> doesn't meet the bound expectation on C<?>; since it it
spec'ed to be:

CloneableMap<K, V extends Cloneable<V>> 

which means that, it needs:

C<?> <: Cloneable<C<?>>

however per construction, this isn't true as:
   interface C<T extends C<T>> implements Cloneable<T> {}

which here means:

C<?> <: Cloneable<?>   (and not Cloneable<C<?>>)

remember that even if String <: Object, List<String> is not a subtype of
List<Object>
Comment 3 Matthew Hall CLA 2005-06-20 11:26:28 EDT
I'm guessing that you use <: as a left-to-right "implements" or "extends" 
relationship.

I get what you're saying.  Do you see a way I could rearrange this to work?  
Right now it appears that because I'm not properly expressing the guarantee 
that a Cloneable creates clones of the same class, I can only implements 
Cloneable<T> *once* in a class heirarchy.  Given the following interface 
heirarchy:

interface I extends Cloneable<I> {}

interface A extends I {}
interface B extends A {}
interface C extends A {}

interface D extends I {}
interface E extends D {}
interface F extends D {}

I'm not restricted from refining the return type of clone() in each interface, 
however I can't create a CloneableMap<?, A> because A implements Cloneable<I>, 
not Cloneable<A>.  I can only instantiate a CloneableMap<?, I>.  And I can't 
refine interface A so it extends Cloneable<A>.
Comment 4 Philipe Mulet CLA 2005-06-20 13:09:23 EDT
'<:' denotes subtype relationship (from the JLS).

As for the latter issue, this is indeed mandated by the language that you can
only extend/implement one instance of a given generic type.
I do not see any workaround to this.

Added GenericTypeTest#test766-767