on diamond and evolution

Maurizio Cimadamore Maurizio.Cimadamore at Sun.COM
Fri Nov 6 06:09:17 PST 2009


Hi,
Reinier is correct. This code:

public static <T> List<T> list(T t) {
       ...
   }

   public static void main(String[] args) {
     List<Object> l = list("foo");
   }


currently does not work, but I think it would be nice if it would. 
However this should be handled as a separate inference enhancement that 
we can pursue (thought not necessarily in the jdk 7 timeframe).

In the immediate future there will be no changes to javac's inference 
algorithm. Moreover, after the diamond implementation switch, diamond 
will also be relying on javac's type inference (which means only one 
inference scheme for all cases, diamond and methods).

Maurizio

Reinier Zwitserloot wrote:
> I believe he meant that, while that doesn't work now, it's feasible that it
> might work later, simply by adding more brains to the inference engine
> (specifically: Letting the inference engine take the target type into
> account). And when that is done, by making the diamond operator consistent
> with this inference, it'll get the ability to do so 'for free'.
>
> Correct me if I'm wrong, too :P
>
> --Reinier Zwitserloot
>
>
>
> On Fri, Nov 6, 2009 at 2:49 PM, Rémi Forax <forax at univ-mlv.fr> wrote:
>
>   
>> Le 06/11/2009 12:31, Maurizio Cimadamore a écrit :
>>     
>>> Hi
>>> Following the recent discussions in this mailing list about the diamond
>>> implementation, I decided to spent some more time in order to figure
>>> out  exactly what it means, in term of language evolution, supporting
>>> the simple approach currently checked in the JDK 7 repository.
>>>
>>> Quick recap:
>>>
>>> *) Simple approach: infers the diamond type using the *only* the
>>> expected type (if available) - similar (if not identical) to 15.12.2.8
>>>
>>> *) Complex approach: infers the diamond type using a full inference
>>> round (arguments + return type) - 15.12.2.7 + 15.12.2.8
>>>
>>> *) Full-complex approach: an hypothetical approach that is based upon
>>> complex (see above) - in addition, it throws the constraint about the
>>> expected type earlier in the inference process (precisely in 15.12.2.7),
>>> so that argument type inference cannot infer a type that, by being too
>>> specific, is incompatible with the expected type.
>>>
>>> As it was shown in [1] there is no subset relationship between simple
>>> and complex - that is the two inference routines simply yield different
>>> results - in this sense, the simple approach cannot be viewed as a
>>> proper subset of the complex approach.
>>>
>>> This is bad for evolution, as pointed out by Neal. My argument was that
>>> there existed a full-complex approach capable of subsuming both simple
>>> and complex at the same time - this would have allowed for further
>>> language extension (e.g. argument type inference) w/o breaking
>>> compatibility.
>>>
>>> After a more detailed analysis I found out that the full-complex
>>> approach, while feasible is not fully backward compatible with the
>>> simple approach. The full-complex works nicely when the attribution
>>> context has an expected type (because the type inferred for diamond is
>>> compatible with the types inferred by both approaches). However, when
>>> the attribution context is missing an expected type, things don't go as
>>> planned. Here's a simple example:
>>>
>>> class Foo<X>  {
>>>   Foo<X>(X x) {}
>>>   Foo<X>  get() { return this; }
>>> }
>>>
>>> Foo<Object>  = new Foo<>(1).get();
>>>
>>> With the simple approach this works just fine. The argument type is
>>> never considered during inference - because of that, diamond ends up
>>> inferring Object (the bound of X) for X. Calling get() on a Foo<Object>
>>> yields a Foo<Object>  which is compatible with the LHS type in the
>>> assignment.
>>>
>>> Now suppose that in some release>7 we enable the full-complex approach.
>>> What would happen to this particular example? When a type is to be
>>> inferred for Foo<>, both argument and expected type are considered. Here
>>> there's no expected type (the LHS type of the assignment is the expected
>>> type for the get() call) - so full-complex is roughly equivalent to
>>> existing 15.12.2.7. Which (again) would yield a different type than the
>>> one returned by the simple approach - namely Foo<Integer>  instead of
>>> Foo<Object>. Now, calling get() on Foo<Integer>  would yield Foo<Integer>
>>> which is clearly incompatible with Foo<Object>. Btw: I'm not saying that
>>> accepting the above code is a must - an inference scheme can either
>>> accept (as simple) that or reject that (as complex); however, if we now
>>> choose a scheme that allows it, future releases will also have to cope
>>> with that, and we have seen clearly that even the full-complex approach
>>> cannot guarantee that.
>>>
>>> Bottom line: the full-complex approach doesn't represent a viable
>>> alternative for reconciling the diamond inference routine with the
>>> standard javac's method inference routine - as a result, the simple
>>> approach currently implemented in the JDK7 would represent an obstacle
>>> for future language extensions. In principle, it would be possible to
>>> limit the scope of the simple approach to those contexts that have an
>>> expected type, so that the simple approach would fail when no expected
>>> type is given. While this is clearly a forward compatible solution, we
>>> believe it would be unnecessarily restrictive and ultimately not worth
>>> pursuing it.
>>>
>>> Recalling from my earlier emails, the biggest disadvantage of the
>>> complex approach vs. simple is the following example:
>>>
>>> Foo<Object>  foo =  new  Foo<>(1);
>>>
>>> However I believe this can eventually be fixed by an inference overhaul
>>> on the lines of the full-complex approach, so that the argument type
>>> inference would take into account the expected return type (thus
>>> inferring Object instead of Integer). Actually, that's also the biggest
>>> advantage of the complex approach: any change that will positively
>>> affect javac's standard type-inference, will positively affect diamond
>>> as a side-effect.
>>>
>>> The next obvious step is to simply switch the diamond implementation in
>>> the jdk 7 repository, as we already have a working prototype (see [2]).
>>>
>>> Thanks to everyone for participating in the discussion and helping in
>>> making Java a better language.
>>> Maurizio
>>>
>>> [1] -
>>> http://mail.openjdk.java.net/pipermail/coin-dev/2009-August/002165.html
>>> [2] - http://cr.openjdk.java.net/~mcimadamore/6840638/webrev.1/
>>>
>>>
>>>       
>> Hi Maurizio,
>> Correct me, If I'm wrong. You want to change the already existing
>> inference algorithm
>> in order to be able to compile that code:
>>
>> public static <T> List<T> list(T t) {
>>       ...
>>   }
>>
>>   public static void main(String[] args) {
>>     List<Object> l = list("foo");
>>   }
>>
>> And use the same algorithm for the diamond syntax.
>>
>> Rémi
>>
>>
>>     
>
>   




More information about the coin-dev mailing list