Incoherent invocation type inference?
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jan 16 15:25:11 UTC 2017
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
More information about the compiler-dev
mailing list