lambda inference bug

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Sep 5 06:30:47 PDT 2011


On 05/09/11 14:11, Rémi Forax wrote:
> On 09/05/2011 01:11 PM, Maurizio Cimadamore wrote:
>> Hi,
>> forget my earlier comment (I misread your example) - this should 
>> indeed compile, as E gets a lower bound from the first actual 
>> argument. This has been now fixed in the lambda-repo.
>>
>> Maurizio
>
> Hi Maurizio,
> thank you for the fast fix.
>
> Could you explain me the difference between the inference used by 
> default by javac
> and the complex inference ?
Leaving lambda aside for a moment (simpler) - suppose you have the 
following method declaration:

<S> void m(List<S> ls) { ... }

and that you want to call 'm' as follows;

m(new ArrayList<>);

in a perfect world where inference in method context would work as 
expected (;-)) there is a problem with the above source: we are supposed 
to infer the type-variable S from the type of the actual argument 
applied to the method; however, the actual type itself needs some 
inference to be performed.

The standard javac policy is to issue an inference error in such cases 
(cyclic inference - see example below with lambdas). However, I've been 
working at a more aggressive inference scheme that tries to 'unstuck' 
the inference process in a backward compatible way:

*) first, the type of the actual argument is inferred w/o the expected 
type (i.e. using Object). Thus, the actual is first inferred to be 
ArrayList<Object>

*) then, the newly instantiated actual is used to carry on the inference 
of the formal (thus, S == Object).

Note that, while the result is not as specific as we would like it to 
be, on the other hand the compiler would be able to compile this 
example, and to have an answer that would be compatible with what the 
compiler inferred in JDK 7.

With inference of lambda formals, it is sometimes possible to end up 
with a situation that is morally equivalent to the one illustrated above 
- an example is:

interface SAM<X> {
List<X> m();
}

class Test {
<Z> void m(SAM<Z> sz) {  }

{ m(#{ -> new ArrayList<>() }); }
}

The above doesn't compile by default - however it can be made to compile 
by enabling the -XDcomplexinference flag.

We still have to decide as to whether this 'aggressive' mode will be the 
default behavior for the javac compiler in JDK 8. We believe this could 
be an advantage esp. if the scope of target type-inference is expanded 
to support inference in method context.

Maurizio

>
> Rémi
>
>>
>> On 05/09/11 09:20, maurizio cimadamore wrote:
>>>> public class ReducerBug {
>>>> >     interface Reducer<E, V>  {
>>>> >       public V reduce(E element, V value);
>>>> >     }
>>>> >
>>>> >     private static<E>  int reduce(Iterable<? extends E>  
>>>> iterable, int
>>>> >  initialValue, Reducer<? super E, Integer>  reducer) {
>>>> >       int value = initialValue;
>>>> >       for(E e: iterable) {
>>>> >         value = reducer.reduce(e, value);
>>>> >       }
>>>> >       return value;
>>>> >     }
>>>> >
>>>> >     public static void main(String[] args) {
>>>> >       java.util.List<Integer>  l = java.util.Arrays.asList(1, 2, 3);
>>>> >       int result = reduce(l, 0, #{ e, v ->  e + v});
>>>> >       System.out.println(result);
>>>> >     }
>>>> >  }
>>
>



More information about the lambda-dev mailing list