Interaction between covariance and generics
This is a follow-up of sorts to the "Implied types" thread but you don't have to read it to understand. Since responders on this forum often complain that they can't help because they don't understand the context; I give some context below, perhaps too much.
* There is a matching pair of Tag and Type classes at the top of the hierarchy and then a matching triplet of Foo, FooTag and FooType classes underneath.
* As in the earlier thread there is a 1-to-1 correspondence between Foo and FooTag classes. There is AFAICT no way to convey this to the compiler but it makes certain unchecked casts safe perfectly safe within the context of this system.
* Type classes are Class-like in character and thus parametrized over the Tag class of the same level. FooType is implemented as a kind of Enum and serves as a sort of Foo/FooTag ontology.
* FooTag and FooType extend Tag and Type respectively but FooType has an extra type parameter and thus extends Type only w/r to the first parameter; I suspect this is this root of my troubles.
* Tag classes have a getType method that is meant to be covariantly specialized as we move down the hierarchy.
* Finally, for convenience both Foo and FooTag have a getType method which, for matching Foo and FooTag instances, should return the exact same object. The obvious way to achieve this is through delegation but these are interfaces, so I implement this delegation in an AbstractFoo class and that is where things go awry.
Here is the code; I am only showing the top 3 levels: next comes a family of concrete classes implementing Foo by extending AbstractFoo, i.e., Foo1, Foo2 etc with matching FooTag1, FooTag1 etc.
// first level
interface Type<Textends Tag>{}
interface Tag{
Type<?extends Tag> getType();
}
// second level
class FooType<Textends FooTag, Fextends Foo><T>>implements Type<T>{}
interface FooTagextends Tag{
<Textends FooTag> FooType<T, Foo><T>> getType();
}
interface Foo<Textends FooTag>{
T getTag();
FooType<T, Foo><T>> getType();
}
// third level
abstractclass AbstractFoo<Textends FooTag>implements Foo<T>{
public FooType<T, Foo><T>> getType(){
return (FooType<T, Foo><T>>)getTag().getType();
}
}
Compilation fails with
reference to getType is ambiguous, both method getType() in Tag and method <T>getType() in FooTag match
return (FooType<T, Foo><T>>)getTag().getType();
^
Covariance seems to be working since the compiler does not complain about overriding Tag.getType with a different return type in FooTag.getType but then there is this error about the ambiguity. I have never seen this before and am a bit clueless as to what is the problem exactly. There is also an unchecked cast warning but that one is inevitable and unproblematic.
NB: From a design point of view I am not stuck since I can implement the delegation in the leaf Foo classes but, first,, that is less convenient (one more method in each class) and, second, I'd still like to understand the nature of the technical problem here.

