Incoherent invocation type inference?
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jan 16 17:03:28 UTC 2017
On 16/01/17 16:49, B. Blaser wrote:
> 2017-01-16 16:25 GMT+01:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
>>
>> On 16/01/17 12:51, Maurizio Cimadamore wrote:
>>> I don't think intersection types are the evil in your example. Even
>>> leaving intersection types aside:
>>>
>>> class Issue {
>>> <T> T get() { return (T)new ArrayList<String>(); }
>>>
>>> void run() {
>>> LinkedList<String> ll = null;
>>> ll = get(); // OK, but will fail at runtime due to unchecked
>>> conversion in get().
>>> }
>>>
>>> public static void main(String... args) {
>>> new Issue().run();
>>> }
>>> }
>>>
>>> So, I guess I'm not exactly sure of what we're trying to improve here?
>> To clarify - what I'm saying here is: the main issue is that get() is
>> promising that ArrayList<String> will be compatible with T. This promise is
>> unsound - as T is basically controlled by client code, so it can be fixed to
>> whatever type the client wants. That's the condition that smells, IMHO.
>>
>> It's true that, as Remi pointed out, there are cases where unchecked
>> conversion and return type inference play well together - as in
>> Collections.emptyList - but there's a big difference in that method:
>>
>> public static final <T> List<T> emptyList()
>>
>> The return type here is not a naked type-variable T - but List<T>. So, while
>> the client can control the parameterization (List<String> vs List<Integer>)
>> it *cannot* control the base type (List vs String).
>>
>> The combination of unchecked return assignment and a naked generic method
>> type-variable return are IMHO always a source of smell in generic code -
>> that's what I was referring to with the Lint digression.
>>
>> As far as intersection types are concerned - I sense that it's easier to add
>> new well-formedness rules about such types rather than changing the way in
>> which inference constraints are set up based on finality of a class. Having
>> such checks would also prevent users from spelling bad intersection types in
>> their code (e.g. a cast with an intersection type target - which is possible
>> since Java SE 8).
>>
>> Maurizio
> Intersections seem to be dangerous only in the case of a naked return
> type variable with no parameter provided ("get()" or "get(null)")
> because get() wouldn't know about the return type constraints. We
> could, for example, update the rule as follows: "emit a lint warning
> if the return type T is a naked type variable infered to an
> intersection type and no constraint is given by the actual arguments"?
>
> Or are you suggesting to modify the rules of intersection types on the
> language side?
I think the Lint warning makes sense for naked return type regardless of
intersections - as in the example I wrote.
Then, for tightening intersections, we could add more rules on the
language side. Note that javac already prevents you from creating an
intersection out of List<Integer> and List<String> (different param of
the same generic interface), so perhaps something about 'final' should
be added to (either as an official, specified check, or just as a Lint one).
Maurizio
>
> Bernard
More information about the compiler-dev
mailing list