poly-expression type inference pothole
maurizio.cimadamore at oracle.com
Thu Jul 4 02:27:35 PDT 2013
On 04/07/13 10:16, John Rose wrote:
> P.P.P.S. I just noticed this commentary in Part D:
>> • The receiver in a method invocation, field access, etc. (exp.foo()) is not a poly expression because the target type is unknown—it would be impossible to enumerate every type that has a particular member (foo, in this case). There has been some interest in allowing inference to "chain": ina().b(), passing type information from the invocation of b to the invocation of a. This adds another dimension to the complexity of the inference algorithm, as partial information has to pass in both directions; it only works when the erasure of the return type of a() is fixed for all instantiations (e.g.List<T>). This feature would not fit very well into the poly expression model, since the target type cannot be easily derived.
> It looks like what I'm asking for is allowing inference to chain through dot. In that case, my two examples are some what illusory.
> The high-level point is that unless inference can chain through dot, default methods will be much weaker (w.r.t. inference) than static methods, and so APIs will be driven to non-fluent (function-oriented) notations. This is the time to fix it, not later, after we've invented lots of APIs.
the problem with your code is that when you have something like:
String r = function(Object::toString).apply(42);
The compiler is type-checking the receiver in isolation, i.e. w/o
looking at the target type - this is a result of the section you quote
Now, w/o a target-type, there aren't enough constraints to type-check
the method reference; type-checking the method reference in fact
requires knowledge of the instantiated functional descriptor parameter
types; however, instantiation on those types depends on being able to
type-check the method reference itself. Hence the loop. You are right
that the spec doesn't talk about inference loops - javac is giving up in
those situations, while the spec comes up with a default instantiation
for the unconstrained variables - which is probably not what you want.
That's just a cosmetic difference anyway.
Now, to cheer you up; the first example you posted works now as a result
of the improvements we added to handle unoverloaded method references.
Here there's a trick at our disposal to unblock the loop: since
Object::toString is unambiguously pointing to a given method
(Object.toString), there's no reason why the compiler should block
type-checking of that method reference waiting for the descriptor
parameter types. In fact, the compiler now goes ahead and uses the
information derived during the type-checking of the method reference in
order to derive a possibly meaningful) instantiation for the inference
variables in the target functional descriptor.
More information about the lambda-dev