JSR 335 Lambda Specification, 0.6.0

Dan Smith daniel.smith at oracle.com
Mon Dec 10 13:30:26 PST 2012


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).

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?

> In section 18.2.1.2, 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.

> Section 18.2.1.3
> 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 18.2.1.3.

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.

> 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<>'.

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, 15.12.2.5.

—Dan


More information about the lambda-spec-observers mailing list