Parametrized method and cyclic inference
Remi Forax
forax at univ-mlv.fr
Fri Nov 2 17:35:47 PDT 2012
On 11/02/2012 11:19 PM, Dan Smith wrote:
> On Nov 2, 2012, at 10:48 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
>> Hi guys,
>> I've tried to take a big corpus of code and to refactor all inner-classes to use lambda instead.
>>
>> The good news is that on 23 uses of inner classes, 20 can be retrofited to use lambdas
>> because the target type is a SAM and they don't require a strong identity (this is not used).
>> The bad news is that among the 20 that can be retrofited, 17 can not be retrofited using
>> the syntax that doesn't specified the type of the formal parameter i.e. the natural syntax
>> because the compiler complains that there is a cyclic inference.
>>
>> The 17 snippets of code can be covered by 3 cases:
>> static <T> void m(T t1, T t2) {
>> // empty
>> }
>>
>> public static void main(String[] args) {
>> m(x -> 3, x -> 4); // case 1
>> Set<Mapper<Integer, Object>> set = Collections.singleton(x -> 3); // case 2
>> List<Mapper<Integer, Object>> list = Arrays.asList(x -> 1); // case 3
>> }
>>
>> To sumarrize, it's currently impossible to call a parametrized method with an untyped lambda,
>> the inference will just choke.
>>
>> I think instead that if there is a cyclic inference,
>> the return type should be used to try to infer the formal parameter type of the lambda,
>> at least, it will solve case 2 and 3.
> Thanks! Feedback from real code is very useful.
> #2 and #3 are interesting. In general, we've nailed down a strategy for inference that depends on a target type. But this is special.
>
> The target type is an inference variable, T. Note that this is _not_ a functional interface. Everything we've done to this point has bailed out early if the target of a lambda is not a functional interface.
>
> An alternative would be to initially hope that T will be a functional interface, wait for T to be resolved, and then go from there. There are aspects of that that feel a little more complex than I would like, but it's probably doable.
I think that if we have cyclic inference, it's better to back propagate
the result type and to try to use it as a function interface.
By example, for
Set<Mapper<Integer, Object>> set = Collections.singleton(x -> 3);
Clearly, it's a cyclic inference, because singleton is defined like this
<T> Set<T> signleton(T element),
instead of trying to know if T is a function interface, in my opinion,
it's better to try to infers T from the result type,
here, Set<Mapper<Integer, Object>>, because the return type is Set<T>,
then T is Mapper<Integer,Object>,
and now you can restart your inference of the lambda expression with the
type of T.
Note that this algorithm also works with diamond syntax which is the
other expression with lambda expression
that need the target type, i.e. works backward in the type checker.
Rémi
More information about the lambda-spec-experts
mailing list