Incoherent invocation type inference?
B. Blaser
bsrbnd at gmail.com
Mon Jan 16 18:33:09 UTC 2017
2017-01-16 18:03 GMT+01:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
>
>
> 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.
Ok for this first rule.
> 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).
For the final class, I would be tempted to say that the equality
constraint is "obvious"; but if it isn't compliant with the language
specification, we could explore a Lint warning too...
Bernard
> Maurizio
More information about the compiler-dev
mailing list