Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java type inference with lower bounded types

Why is it that Java can infer the common ancestor of multiple upper-bounded types, but not of lower-bounded types?

More specifically, consider the following examples:

static class Test {

    static <T> T pick(T one, T two) {
        return two;
    }

    static void testUpperBound() {
        List<? extends Integer> extendsInteger = new ArrayList<>();

        // List<? extends Integer> is treated as a subclass of List<? extends Number>
        List<? extends Number> extendsNumber = extendsInteger;

        // List<? extends Number> is inferred as the common superclass
        extendsNumber = pick(extendsInteger, extendsNumber);
    }

    static void testLowerBound() {
        List<? super Number> superNumber = new ArrayList<>();

        // List<? super Number> is treated as a subclass of List<? super Integer>
        List<? super Integer> superInteger = superNumber;

        // The inferred common type should be List<? super Integer>,
        // but instead we get a compile error:
        superInteger = pick(superNumber, superInteger);

        // It only compiles with an explicit type argument:
        superInteger = Test.<List<? super Integer>>pick(superNumber, superInteger);
    }
}
like image 972
shmosel Avatar asked Dec 26 '14 04:12

shmosel


People also ask

What is type inference in Java with example?

Consider the following example: MyClass<Integer> myObject = new MyClass<>(""); In this example, the compiler infers the type Integer for the formal type parameter, X , of the generic class MyClass<X> . It infers the type String for the formal type parameter, T , of the constructor of this generic class.

Which syntax would you use to express a wildcard with a lower bound of some type?

A lower bounded wildcard is expressed using the wildcard character ('? '), following by the super keyword, followed by its lower bound: <? super A>. Note: You can specify an upper bound for a wildcard, or you can specify a lower bound, but you cannot specify both.

How does type inference work in Java?

Type inference represents the Java compiler's ability to look at a method invocation and its corresponding declaration to check and determine the type argument(s). The inference algorithm checks the types of the arguments and, if available, assigned type is returned.

Does Java 7 support type inference?

Java SE 7 supports limited type inference for generic instance creation; you can only use type inference if the parameterized type of the constructor is obvious from the context.


1 Answers

I think I can explain why Java differentiates between a lower-bounded and upper-bounded type.

Trying to infer a common lower bound can fail when incompatible bounds are used, for example Integer and Long. When we're using an upper bound, it's always possible to find some common upper bound, in this case List<? extends Number>. But there's no common lower bound of List<? super Integer> and List<? super Long>. The only safe option in case of such a conflict would be to return List<? extends Object>, synonymous with List<?>, meaning "a List of unknown type".

Now, arguably we could have resorted to that only when there actually are conflicting bounds, as opposed to the case in my question. But maybe it was decided to take the easy way out and not assume there's a common lower bound unless explicitly specified.

like image 108
shmosel Avatar answered Oct 05 '22 23:10

shmosel