2

I'm trying to override a method that returns an instance of the class that it is declared in, which changes the parameters of the class between the instance that the method is called on and the instance returned by the call. I would like to be able to return an instance of the Overriding_Attempt class from the overriding method.

It's not clear to me why Overriding_Attempt<X> is not equivalent to DuoClass<X,ContainerClass<X>> given the extension in the declaration of Overriding_Attempt. I would like to be able to return this more specific instance of DuoClass<X,ContainerClass<X>>. The error I get is The return type is incompatible with DuoClass<A,ContainerClass<A>>.methodToOverride()

This issue is very much related to the Nested Parameters question posted here.

Also of note: Deleting the declaration of parameter Y from Overriding_Attempt seems to cause a signature mismatch such that the error becomes Name clash: The method methodToOverride() of type Overriding_Attempt<A> has the same erasure as methodToOverride() of type DuoClass<A,B> but does not override it. It seems odd that I would need to declare an unused parameter but that's not my main problem.

public class SomeClass {
    
}

public class ContainerClass<A extends SomeClass> {
    
}

public class DuoClass<A extends SomeClass, B extends ContainerClass<A>> {
    
    public <X extends SomeClass, Y extends ContainerClass<X>> DuoClass<X,Y> methodToOverride(X field) {
        return null;
    }
    
}

public class Overriding_Attempt<A extends SomeClass> extends DuoClass<A,ContainerClass<A>> {
    //Error Here: The return type is incompatible with DuoClass<A,ContainerClass<A>>.methodToOverride()
    public <X extends SomeClass, Y extends ContainerClass<X>> Overriding_Attempt<X> methodToOverride(X field) {
        return null;
    }
}
Alex Apel
  • 21
  • 3

1 Answers1

0

I'm pretty sure you don't actually want typed methods - ie X and Y are actually A and B, so you should not add types X and Y to the method.

Given that, you need a self-referencing type:

public class DuoClass<A extends SomeClass, B extends ContainerClass<A>, T extends DuoClass<A, B, T>> {
    public T methodToOverride(A field) {
        return null;
    }
}

public class Overriding_Attempt<A extends SomeClass> extends DuoClass<A, ContainerClass<A>, Overriding_Attempt<A>> {
    public Overriding_Attempt<A> methodToOverride(A field) {
        return null;
    }
}

The generic "knot" you were facing is that the compiler doesn't know that the return type DuoClass<A, B> is the same class is the declaring class - it could theoretically be any subclass, but you want it to be the declaring class.

By adding an extra type for the declaring type, you lock in the reference to the declaring type and can refer to it a T.

Bohemian
  • 365,064
  • 84
  • 522
  • 658
  • Unfortunately I think I do need a typed method because it allows me to change between classes that extend `SomeClass` as `methodToOverride` is called. In short `A != X`. – Alex Apel Jul 24 '20 at 04:51
  • @alex that’s not how genetics work. By making the method typed (ie adding X and Y) you’re saying that the method of an implementation can accept and return *any* types of objects as long as they are with the bounds defined, irrelevant to the types of the class the method is on. I seriously doubt that is what you want. It would be a good idea to add concrete examples with demonstrative types (ie not “SomeClass” but something meaningful) to better describe what you’re trying to do. – Bohemian Jul 24 '20 at 10:22