Self-bounding generics
How do I decrypt “Enum<E extends Enum<E>>”?
Self-Bounding generics is quite similar to CRTP(Curiously Recurring Template Pattern), but somewhat different. See the following example:
class Parent<T extends Parent<T>> { private int fVal; public Parent() { setVal(0); } public Parent(int val) { setVal(val); } public void setVal(int val) { fVal = val; } public int getVal() { return fVal; } public boolean compareTo(T other) { return getVal() == other.getVal(); } } class Sub extends Parent<Sub> { } class Sub2 extends Parent<Sub2> { } public class SelfBounding { public static void main(String args[]) { Sub s = new Sub(); System.out.println(s.compareTo(new Sub())); System.out.println(s.compareTo(new Sub2())); } }
This code raises an error, when compiled: SelfBounding.java|26| compareTo(Sub) in Parent<Sub> cannot be applied to (Sub2).
Let’s see why. Firstly, what is Sub actually? The Sub extends Parent. Specifically, Parent<Sub>. Parent is a parameterized class. So, T should satisfy ‘T extends Parent<T>.’ Here, T is Sub. So, Sub should satisfy ‘Sub extends Parent<T>.’ Obviously, Sub satisfies this constraints because Sub is actually subclassing Parent<Sub>.
Okay, that makes sense. But, why should we bother?
The thing is that the Sub is inhering a method: compareTo(). In the Parent, compareTo is declare to receive an argument of type T. In Sub, T is obviously Sub. Which means that Sub class is inheriting a method whose argument/return type is exactly the same as itself.
Still, there’s an problem. Consider the following:
class Sub extends Parent<Sub> { } class Sub2 extends Parent<Sub> { }
In this case, Sub2 extends Parent<Sub>. So, in Parent, T is Sub. And, obviously, Sub is subclassing Parent<Sub>. Hence, Sub2 inherited a method which gets an argument of type Sub. At this point, everything becomes a mess.
This is why this pattern is hard to apply in practice. There is a hot debate about this issue. Come and play: http://www.artima.com/forums/flat.jsp?forum=106&thread=136394&start=15&msRange=15