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