Trouble with wildcards

Zhong Yu zhong.j.yu at gmail.com
Tue Dec 17 15:48:22 PST 2013


In the instance method case
    p1.and(p2)
there is no type variable to be inferred, all types are fixed.

In the static case,
    staticAnd(p1,p2)
there is a "floating" variable T to be inferred, and javac can
"adjust" T to make the the code legal. The freedom given by the
floating T is so much that even the following code compiles

    Predicate<? super Serializable> p1 = null;
    Predicate<? super CharSequence> p2 = null;
    Predicate<? super String> p3 = staticAnd(p1,p2);

Zhong Yu

On Tue, Dec 17, 2013 at 4:50 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> On 12/17/2013 09:35 PM, Zhong Yu wrote:
>>
>> The static method works because it has an extra type parameter, which
>> gives javac the freedom to make things work. The instance and() method
>> has no such freedom (unless we give it a type parameter <S extends T>)
>>
>> Zhong Yu
>
>
> The instance method and() is called on a Predicate<? super T>, and Predicate
> is declared as class Predicate<T>, here T is already your extra type
> variable.
>
> Rémi
>
>
>>
>> On Tue, Dec 17, 2013 at 1:46 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>>
>>> On 12/17/2013 07:21 PM, Dan Smith wrote:
>>>>
>>>> On Dec 16, 2013, at 7:42 AM, Paul Sandoz <paul.sandoz at oracle.com> wrote:
>>>>
>>>>> Hi Remi,
>>>>>
>>>>> Reducing it down a little:
>>>>>
>>>>> import java.util.*;
>>>>> import java.util.function.*;
>>>>>
>>>>> class A {
>>>>>
>>>>>    static class X {};
>>>>>    static class Y extends X {};
>>>>>
>>>>>    public static void main(String[] args) {
>>>>>      Predicate<X> px = x -> x instanceof X;
>>>>>      Predicate<Y> py = y -> y instanceof Y;
>>>>>
>>>>>      Predicate<? super Y> psy = px;
>>>>>
>>>>>      Predicate<? super Y> superyandy = psy.and(py);    // <-- error
>>>>>      superyandy.test(new Y());
>>>>>    }
>>>>> }
>>>>>
>>>>> $ javac -Xdiags:verbose A.java
>>>>> A.java:15: error: method and in interface Predicate<T> cannot be
>>>>> applied to given types;
>>>>>    Predicate<? super Y> superyandy = psy.and(py);    // <-- error
>>>>>                                         ^
>>>>>    required: Predicate<? super CAP#1>
>>>>>    found: Predicate<Y>
>>>>>    reason: argument mismatch; Predicate<Y> cannot be converted to
>>>>> Predicate<? super CAP#1>
>>>>>    where T is a type-variable:
>>>>>      T extends Object declared in interface Predicate
>>>>>    where CAP#1 is a fresh type-variable:
>>>>>      CAP#1 extends Object super: Y from capture of ? super Y
>>>>> 1 error
>>>>>
>>>>>
>>>>> It's confusing...
>>>>
>>>> The concrete explanation: the 'and' method of the type
>>>> Predicate<[something]>, where [something] is some type that is a supertype
>>>> of Y (written CAP#1 in the error message), requires a Predicate<? super
>>>> [something]>.  Is a Predicate<Y> a Predicate<? super [something]>?  No.  For
>>>> example, consider the case in which [something] is Object.
>>>
>>> I disagree, Predicate<Y> is a Predicate<? super [something]> because Y
>>> can capture
>>> ? super [something], otherwise it means that 'and' should be a static
>>> method and not an instance method.
>>>
>>> The following code compiles:
>>> static <T> Predicate<T> staticAnd(Predicate<? super T> that, Predicate<?
>>> super T> other) {
>>>       ...
>>> }
>>>
>>> Predicate<? super String> p1 = null;
>>> Predicate<? super String> p2 = null;
>>> Predicate<? super String> p3 = staticAnd(p1,p2);
>>>
>>> but not
>>>     Predicate<? super String> p3 = p1.and(p2);
>>> which is not very logical.
>>>
>>>> The abstract explanation: we accept that 'px.and(py)' is a type error,
>>>> right?  So it certainly doesn't make any sense that _up-casting_ px to one
>>>> of its supertypes (Predicate<? super Y> in this case) would provide some
>>>> functionality that px itself doesn't have.
>>>>
>>>> —Dan
>>>
>>> Rémi
>>>
>>>
>


More information about the lambda-dev mailing list