next up previous index
Next: Generic arrays Up: Typing an order relation Previous: Wildcards   Index

Going a step further

For many applications this declaration of SortedList will be adequate. However, it is not difficult to see that the declaration

public class SortedList<E extends Comparable<E>> {...}
is in fact more restrictive than the raw declaration
public class SortedList<E extends Comparable> {...}
The latter condition is satisfied if there is some type X such that E extends X and X implements Comparable<X>. The former insists that X equals E.

Here is an example to illustrate the issue. The definition

public abstract class Shape implements Comparable<Shape> {
    public abstract int area();
    public int compareTo(Shape other) {
        return other.area() - this.area();
    }
}
implies that Shapes have areas which can be used to order them. Here are two particular kinds of Shape:
public class Square extends Shape {
    private int side;
    ...
    public int area() {
        return side * side;
    }
}
public class Rectangle extends Shape {
    private int base, height;
    ...
    public int area() {
        return base * height;
    }
}
each using its own appropriate definition of area().

Using either of the definitions

public class SortedList<E extends Comparable> {...}
or
public class SortedList<E extends Comparable<E>> {...}
we can construct sorted lists of Shapes, e.g. by
SortedList<Shape> list = new SortedList<Shape>();
list.insert(new Square(1));
list.insert(new Square(2));
list.insert(new Rectangle(1,2));
The reason is that Shape does indeed implement Comparable<Shape> and both Squares and Rectangles are legitimate values for Shape variables.

But suppose now we wish to construct a sorted list of Squares alone by the code

SortedList<Square> list = new SortedList<Square>();
list.insert(new Square(1));
list.insert(new Square(2));
where you should note the change in the first line of code, from before. This is legitimate using the raw definition
public class SortedList<E extends Comparable> {...}
but not legitimate according to
public class SortedList<E extends Comparable<E>> {...}
The reason is that the compiler will accept that Square implements Comparable, as a raw untyped interface, because Square extends Shape and Shape implements Comparable<Shape>. But the compiler will not accept that Square implements Comparable<Square> because it was not declared to do so.

This may seem perverse. A Square is comparable to any Shape hence a fortiori to any Square. So why does Square not implement Comparable<Square>? The answer is that Java 5 does not undertake to deduce any such rules about the relations between types. If G is some generic type declaration, no subtype relations between G<S> and G<T> are inferred by the compiler from subtype relations between S and T.

There is, however, a simple, if visually unappealing, way around. The reason why

public class SortedList<E extends Comparable> {...}
permits the construction of SortedList<Square> is that the, now deprecated, raw bound <E extends Comparable> is satisfied by a type E if there is some type X such that E extends X and X implements Comparable<X>. Java 5 has an approved syntax that permits the expression of exactly such a bound, consistently with full typing of the Comparable interface, namely
public class SortedList<E extends Comparable<? super E>> {...}
The expression ? is a wildcard which is matched by any type. This means that ? super E is matched by any type which is a supertype of E, so that
E extends Comparable<? super E>
is matched by a type E if there is some type X such that E extends X and X implements Comparable<X>. This is exactly what is needed. It follows that SortedList<Square> is now a legitimate type because Square extends Shape and Shape implements Comparable<Shape>.

Whew!

The issues discussed here are mainly of interest to the developer. The user will normally just use a simple declaration such as

SortedList<Float> list = new SortedList<Float>();
and all will behave as expected. The task of the developer is to ensure good behaviour in the widest range of circumstances in which good behaviour can legitimately be expected.


next up previous index
Next: Generic arrays Up: Typing an order relation Previous: Wildcards   Index
Peter Williams 2005-06-07