Heinz Kabutz has a terrific article entitled “Strategy Pattern with Generics”. There’s lots of reasons I like it, but here’s one: it demonstrates a legitimate and pretty comprehensible use of the mind-bending generics syntax MyClass<T extends MyClass<T>>. This is most commonly seen in the Enum class: Enum<E extends Enum<E>>. Thanks to Heinz, I think I finally understand this.
This recursive definition even baffles the experts. In “Generics Considered Harmful” Ken Arnold — a Sun employee, no less — says that the fourth edition of Sun’s own book glosses over trying to explain this recursive Enum definition, and certainly he’s given up trying.
So taking my lead from Heinz’s article let me have a go:
The construct MyClass<T extends MyClass<T>> is used when MyClass needs to use the type of its subclass. It is needed when it’s not good enough to know that it’s dealing with a subclass, but it has to be the subclass which is the type of the derived instance.
In Heinz’s case his version of MyClass calls a method which necessarily takes as a parameter an object of the subclass itself — not a subclass, and not MyClass, but a strict subclass of MyClass.
In the case of Enum it has a method called getDeclaringClass() which returns the class of the enum itself — that is, the subclass of Enum.
As Heinz points out, it would be reasonable to declare the top level class as MyClass<T extends MyClass>, but as MyClass is generic it’s polite to show this.
By the way, Ken Arnold dislikes generics because he says they’re an over-complicated solution to the problem of making type-safety mistakes:
I have yet to find someone who believes this [generics] to be a major source of error in their code, compared to other problems.
To this I’d say there’s another justification for generics, and arguably a more important one: it makes the developer’s intentions much clearer. A list used to be just a list. But as Gilda Bracha says in his definitive tutorial (PDF):
What if programmers could actually express their intent, and mark a list as being restricted to contain a particular data type? This is the core idea behind generics.
Yes, generics can be complicated. But I think they do make sense, and increasingly more so.