[lvti] Non-denotable types
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Fri Jul 14 10:03:18 UTC 2017
On 14/07/17 06:15, Tagir Valeev wrote:
> Hello!
>
> When thinking about local variable type inference, I noticed that lambda
> parameter type inference in Java 8 is sometimes similar. For example, we
> can declare the following method:
>
> static <T> void var(T t, Consumer<? super T> cons) {
> cons.accept(t);
> }
>
> Then Java 8 code like this:
>
> var(theValue, theVariable -> {
> codeBlock;
> });
>
> Is equivalent to LVTI code like this:
>
> var theVariable = theValue;
> codeBlock;
Yep - this is how lambda implicit parameters work in JDK 8/9.
>
> Apparently this does not work for non-denotable types. I checked the
> non-denotable types section in [1]: seems that lambda parameter inference
> infers to non-denotable type as it described in this section, which already
> produces "surprising" results:
>
> void test(List<?> l1, List<?> l2) {
> var(l1, l3 -> {
> l3 = l2; // error
> l3.add(l3.get(0)); // error
> });
> }
>
> Shouldn't we expect a consistency here? There's already a kind of variables
> in Java (lambda parameters) for which non-denotable types are inferred. It
> looks strange to me that two kinds of variable inference work in different
> manner.
We had many discussions on this very topic. In general we agree that
it's bad having two different inference schemes for doing similar
things. That said, there are distinctions to be made, as implicit lambda
parameter inference is _not_ an inference process that can be applied in
isolation, by adjusting each parameter. The way this works is that you
infer a _target_ (not a parameter type) and then you derive the
parameter type from the target, under the constraint that the parameter
type must be whatever is needed to make the lambda 'override equivalent'
with the functional descriptor induced by the target.
In LVTI the inference process is more straightforward: you start from an
expression type (the initializer) and you derive a type from it (the
type for the 'var'), which will need to be some upper bound of the type
you started with.
Being consistent here could mean two things: either allow non denotable
types in 'var', or disallow non-denotable types in implicit lambdas. The
first path seems 'easier' - although it might expose a 'feature' that
many people would probably not even have realized it's there. The latter
would be safer from a language/type-system design perspective, but it
comes with a source compatibility price. We are currently discussing
this and running experiments to see which approach would work best - so
expect to hear something on this topic soon.
Cheers
Maurizio
>
> With best regards,
> Tagir Valeev
>
> [1] http://openjdk.java.net/jeps/286
More information about the amber-dev
mailing list