Search code examples
javagenerics

Why is a wild card type argument not within bounds in wrapper around a selfreferring type


I have an interface that contains methods that return or require instances of the imlementing type. To accomplish this I create a type variable of the form U extends I<U> to use as the return type. The intention of course being that U is the implementing class:

interface SelfReferringInterface<U extends SelfReferringInterface<U>> {
}

Now I have an implementing class that contains an unrelated type variable:

class RestrictingType<T> implements SelfReferringInterface<RestrictingType<T>> {

}

And a class that wraps around an instance of a SelfReferringInterface:

class Wrapper<T extends SelfReferringInterface<T>> {
}

Somehow I get a type inference error for Wrapper types that take a wild card instance of RestrictingType:

public class Main {

        public static void main(String... args) {
                // This type checks
                SelfReferringInterface<?> test1;
                // This too
                RestrictingType<?> test2;
                // And this
                Wrapper<RestrictingType<Object>> test3;
                // This fails
                Wrapper<RestrictingType<?>> test4;
                // Interestingly this does succeed
                Wrapper<? extends RestrictingType<?>> test5;
        }
}

Compiling this gives the following error:

Main.java:23: error: type argument RestrictingType<?> is not within bounds of type-variable T
                Wrapper<RestrictingType<?>> test4;
                                       ^
  where T is a type-variable:
    T extends SelfReferringInterface<T> declared in class Wrapper
1 error

Why is RestrictingType<?> not within the bounds of T? And why is the functionaly similar ? extends RestrictingType<?> no problem?


Solution

  • Wrapper<RestrictingType<T>> works for any given type T because we know that Restricting<T> implements SelfReferringInterface<RestrictingType<T>>. However, Wrapper<RestrictingType<?>> does not work because Restricting<? #1> may not implement SelfReferringInterface<RestrictingType<? #2>>. The wildcard ? means unknown type, and they may be two different unknown types in the two places.

    Here is another way to see why this must be: Suppose that your Wrapper<T> class can hold multiple items of the wrapped type T. Then the bound <T extends SelfReferringInterface<T>> means that the type of any one of the items should implement SelfReferringInterface<type of any other item>, just like how class SortedList<T extends Comparable<T>> means that any one item in the list should be comparable to any other item in the list. However, if you have a Wrapper<RestrictingType<?>>, you will be able to add both RestrictingType<String> and RestrictingType<Integer> items into it, as both those types are subtypes of RestrictingType<?>. However, RestrictingType<String> does not implement SelfReferringInterface<RestrictingType<Integer>>, so the contract is broken.

    As to why Wrapper<? extends RestrictingType<?>> works, I am not really sure exactly, but the ? extends wildcard means you cannot add any items into it, so you cannot use it to break the contract.