JSR 335 Lambda Specification, 0.6.0

Remi Forax forax at univ-mlv.fr
Mon Dec 10 16:01:37 PST 2012

On 12/10/2012 10:30 PM, Dan Smith wrote:
> Thanks for the feedback!
> Caveat on Part G: I haven't touched it since the last round, and need to revise it to get up to speed with our latest work on inference.  That's near the top of my list now...


> On Dec 8, 2012, at 4:47 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>> section 18.2.1:
>> "If the expression is a class instance creation expression or a method invocation,
>> and its type when treated as a standalone expression is /S/, the result is /S →_c T/."
>> There is nothing in the discussion that say why
>> 1) it should not be an error instead of using Object as type argument (compatibility maybe ??)
>> 2) why the inference can not be propagated and wait for the result of the poly expression.
> This will be addressed.
> Keep in mind that this clause only applies where T contains inference variables.  We _do_ use the target in simpler cases in which we don't have to infer the target first (and this is a change from 7, which never used targets in invocation contexts).

yes, I know.

> The new plan for inference is to expand on this, supporting inference variables in generic method invocation targets by hoisting constraints from the nested invocation into the outer invocation, and solving them all together.  I think that's what you're after.


> Your comment about 'Object' could apply in other contexts, too.  Are you suggesting that inference should never use 'Object' as a fallback result, and should produce errors instead?


>   That's a plausible approach (but with some compatibility issues); what's your motivation?

The issue is that if the inference pick Object and fail later, the error 
message doesn't even reference the location where the inference fail so 
it's hard to debug. You have to read the error, find why you don"t have 
the correct signature and backtrack to the place where the inference was 
not able to infer correctly the type variable. So it defeat of the 
cherish principle of Java, fail early.

One month ago a student of mine summary this problem by saying that even 
the inference algorithm doesn't understand the inference algorithm and 
give up boldly.

Now, because the inference will also use the target type in 8, maybe 
there will be less cases where the inference algorithm will pick Object.
And I have no idea about the impact of the compatibility issues.

>> In section, in the discussion, the item 4, I don't understand why it doesn't work.
>> javac agree with me :)
>> interface Sequence<E> {
>> <M> M mapReduce(M base, Function<E, M> mapper, BinaryOperator<M> op);
>> }
>> interface Person {
>> public String name();
>> }
>> public static void main(String[] args) {
>> Sequence<Person> ss = null;
>> String names = ss.mapReduce("", p -> p.name(), (s1, s2) -> s1+", "+s2); // ok
>> }
>> E is person because ss is a Sequence of Person, M is a String because base="", so where is the issue ??
> This will also be addressed.
> This approach to inference variables in lambda parameters—we just don't support it—was a baseline.  The compiler has experimented with various approaches to resolving inference variables as we go; we have a solid plan now, but it needs to be written up.

Ok, cool.

>> Section
>> I'm lost here. Why do you erase the type of the method reference considering it as a lambda without parameter types ??
> Not sure what you mean.  There's no erasure in
> As the discussion points out, the handling of method references mimics both of the previous two areas you asked about: first, like an implicitly-typed lambda, we can't resolve a method reference with inference variables in the parameter types; second, like a nested method invocation, we can't use its target type if the target contains inference variables.
> Both of our new inference strategies will come into play here.

Erasure was not the best term here.
Suppose we have
class MyClass {
   public int myMethod(int t) { ... }
   public long myMethod(long t) { ... }

The question is why do you want to translate 
System.out.println(MyClass::myMethod) to
System.out.println(e -> MyClass.myMethod(e)) instead of translating it into
System.out.println(int e -> MyClass.myMethod(e)) or 
System.out.println(long e -> MyClass.myMethod(e)).

the overloads of myMethod will give you all the combination that are 
possible, you have to see if there are applicable
and then try to find the most specific one.

>> Section 18.2.5
>> I agree that checked exception should not be part of the applicability of a method.
> Good. :-)  In our overload resolution strategy (which I'm planning to send a separate post about), that's where we've ended up.
>> Section 18.5.1 and section 18.5.2,
>> I think you should add a shortcut in the applicability rules.
>> If there is only one method with the correct name and number of parameters, the inference should use the target type.
>> Or said differently, if finding the applicable method fail because a type argument is not found, the compiler should try again inserting the fact that the target type is known,
>> and if only one method is applicable, it's the most specific method.
>> so it will not solve this case like this that we rule out during the face to face meeting:
>> Future<?> future = executor.submit(() -> list.add("foo")); // a Callable or a Runnable
>> but solve
>> ArrayList<String> list = stream.into(new ArrayList<>());
> To get what you want, you'd also need some interleaving of reduction and resolution: we need to solve alpha=String before looking at the argument to 'into'.
> We considered an approach like this, but found it to be too ad hoc, so we settled on our current plan.  We'll be able to handle the nested 'new ArrayList<>'.

yes, it's to ad-hocy, i'm glad that you have find a better way.

> Callable vs. Runnable turns out to be a fairly easy problem to solve: in the most specific test, we just prefer functional interfaces that produce values over functional interfaces that produce 'void'.  We already do a subtyping check, so this is just an extra thing in the same place (informally, in this context, 'void' is a supertype of everything).  See Part F,

I will take a look tomorrow.

> —Dan


More information about the lambda-spec-experts mailing list