Generics and Wildcards


Martin write a post entitled Generics: The Importance of Wildcards


He concludes with:


Unfortunately, C# will not support wildcards or a similar mechanism. The implementation strategy does not allow the introduction of wildcards (generics are implemented in the runtime instead of by type erasure). This is a bit surprising, since the implementation strategy is often claimed to be superior. What disappoints me is that the designers of C# are not willing to admit that subtyping is an issue and that wildcards are a solution.


That’s a very binary statement, when in fact the implementation of generics both in the .NET and Java worlds are exercises in tradeoffs.


I agree that subtyping is an issue, and that wildcards are *a* solution (I don’t know enough to know whether it is the only solution, or whether a solution that worked only on reference types would be interesting.). But, having looked at the implementation of wildcards in Java, they add a fair amount of complexity to the language, and I’m not sure that the added flexibility that they give you is important enough to add language complexity. I do know that when I was talking to C# users, the ability to do this was not one of the things that came up.


When I weigh the speculative benefits there against the known benefits of the .NET implementation – collections of primitive types, for example – it’s pretty clear which one I would prefer.

Comments (6)

  1. Scott Wisniewski says:

    Wildcard types are a good idea, however their implementation in Java is seriously broken.

    In particular, a wildcard can only be successfully used if it appears at the root of a parameterized type tree. Consider something like this :

    public class Pair<T1, T2>

    {

    public T1 First;

    public T2 Second;

    }

    and this:

    public class HashSomeMethods

    {

    public static void Foo(LinkedList<Pair<?, ?>> list)

    {

    //… code here

    }

    public static void Main(String[] args)

    {

    Foo(new LinkedList<Pair<Integer, String>>());

    }

    }

    In examining this code it looks like it should work. However, it doesn’t. Compiling this code with either sun’s javac or the compiler built into eclipse will generate an error at the call site of Foo, stating that LinkedList<Pair<Integer, String>> cannot be converted to LinkedList<Pair<?, ?>>.

    However, if Foo was redefined as follows:

    public static void Foo(LinkedList<?>)

    {

    //… code here

    }

    then it would work.

    The presence of WildCard types introduces polymorphisim that has the same problems as polymorphic arrays: they violate type safety.

    Saying that

    A <: B ==> C<A> <: C<B>

    is, in general, not sound.

    lets say we had something like this:

    class C<T>

    {

    void method(T param)

    {

    //….

    }

    }

    class C2 extends C<B>

    {

    void method(B param)

    {

    //do some B specific stuff to param

    }

    }

    and code like this:

    C<? extends A> x = new C2<B>();

    x.method(new A());

    This code will most certanlty fail at run time because C2<B>.method is expecting an B, but its actually getting an A.

    However, keeping a method expecting a B from getting an A is exactly the type of thing that a type system is soposed to prevent.

  2. Scott Wisniewski says:

    Please Ignore my second point (the one about subtyping).

    Java Wild Card Types require an explicit lower bound to be set before parameters can be passed…

    However, my first point (about wildcard matching being broken) is still valid

  3. Iulian says:

    It works if you change the declaration of Foo as follows:

    public static void Foo(LinkedList<? extends Pair<?, ?>> list) {

    System.out.println(list.get(0).First);

    }

    The explanation is that a type like C<?> is a supertype of any instantiation of the generic class C. However, C<A> and C<B> are unrelated types no matter what is the relation between A and B. So, even though Pair<?, ?> is a supertype of Pair<Integer, String>, LinkedList<Pair<…>> is not a supertype of any other instantiation of LinkedList. But a LinkedList<? … > can be, so you just add the wildcard with the bound you want.

    Iulian

  4. The Java implementation isn’t "seriously broken" by a long shot — but it *is* seriously *hairy*. I played around with each beta as this was being developed, and believe me, there are a lot of dark corners. Some interesting possibilities (ie, wildcards and proper array variance) didn’t end up making the Java 1.5 release because they were just a little *too* hairy to be confident in, given the release time frame.

    I think there is likely some improvement in error messages to be done (the compiler should have suggested the variant type the second poster provided, given the erroneous code of the first poster, etc), but the theory is certainly solid.