In trying to structure my classes in a logical way, I discovered Java's ability to do recursive generics. It is almost exactly what I was looking for structure-wise, but I ran into a problem with abstract classes. I think Foo and Bar would be extremely confusing for this example, so I've named my classes relating to my actual project.
public abstract class GeneCarrier<T extends GeneCarrier<T>> {
protected Gene<T> gene;
//...
}
public class Gene<T extends GeneCarrier<T>> {
//...
}
public abstract class Organism extends GeneCarrier<Organism>{
//...
}
public class Human extends Organism {
public void foo(){
Gene<Human> g; // Bound mismatch: The type Human is not a valid substitute for the bounded parameter <T extends GeneCarrier<T>> of the type Gene<T>
}
}
I thought that the problem might be with the definition of my abstract Organism class, but this also produced a similar error:
public abstract class Organism extends GeneCarrier<? extends Organism>{
//...
}
Is there an inherent problem in trying to use an abstract class with recursive template definitions, or have I made a mistake in the class definitions?
Is there an inherent problem in trying to use an abstract class with recursive template definitions, or have I made a mistake in the class definitions?
It looks like you made a mistake. The recursive bound on Gene's type parameter T necessitates that a type argument of Human should mean that Human is a GeneCarrier<Human>. But it isn't - Human is a GeneCarrier<Organism>.
To implement this pattern correctly, the recursive type parameter should be propagated down the inheritance tree until it reaches what I like to call a "leaf" class, which in this case seems to be Human:
public abstract class Organism<T extends Organism<T>> extends GeneCarrier<T> {
//...
}
public final class Human extends Organism<Human> {
public void foo(){
Gene<Human> g; // valid
}
}
This solves the issue at hand but you should know the ups and downs of using "self-types" in Java (generally known as the Curiously Recurring Template Pattern). I go into detail about implementing this pattern and its pitfalls on this post: Is there a way to refer to the current type with a type variable?
In general I find that developers try to use "self-types" in order to implement a type-safe "copy" method on certain classes (which seems like the case here since your type names are gene-related). When that happens I always recommend trying to decouple the copying responsibility to a separate type, in order to avoid the added complexity of recursive generics. My answer here is an example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With