PROPOSAL: 'final' without explicit type

Reinier Zwitserloot reinier at
Tue Mar 31 05:52:24 PDT 2009

Yes, the type of the RHS of:

final list = foo ? new LinkedList() : new ArrayList();

  is indeed AbstractList<RAW> & Cloneable & Serializable.

The question is: Is that what you make the type of 'list'? That would  
be a novel idea: Now we have type variables that can have intersection  
types, not just expressions. There's nothing inherent in java stopping  
you from doing this for local method variables as you said, but one  
should consider the future impact of this: There is absolutely no way  
to specify intersection types in either java or in any sort of  
reflection tool. Any attempt to add introspection of any sort to types  
of method locals is thus going to be a major issue in the future if we  
allow intersection types for them. I don't think this proposal  
suggests you're allowed to infer the type on fields, regardless of the  
issue of intersection types, but what if that seems useful later on?  
Then either we overhaul java.lang.reflect, -or-, we all of a sudden  
exclude it for fields but allow it (to be backwards compatible) for  
method locals. Ugh. Feels hacky.

I would -strongly- suggest at least for project coin to just not allow  
intersection types at all, period. A future version of java can add  
this support later if it is deemed important. This is analogous to how  
java gained intersection types in the fist place, which wasn't in the  
earlier versions of java. Until intersection types, the following  
expression wasn't even legal:

foo ? new LinkedList() : new Arraylist();

because the type of the expression (and thence also must be the type  
of the third arugment to the ?: operator) is decided by the type of  
the second argument (in the above example, 'LinkedList', and ArrayList  
is not a LinkedList.

this was added without any backwards compatibility issues. The same  
can be done for making method local variables support intersection  

Note that according to Neal, the complete lub of  
Collections.emptyList() and new ArrayList() is JUST 'List<RAW>' and  
nothing else, because one of the intersections is a strict subtype of  
the other. This is nice, because that would mean that even if we don't  
allow intersection types for method-locals, the following:

String foo = someCall();
final list = foo == null ? Collections.emptyList() : Arrays.asList(foo);

would be legal, and would make 'list' be type "List<String>".

A casual glance at large swathes of code finds almost no instances  
where I want to shorten my final method-local declaration by excluding  
the LHS type, but where I would not be able to because the expression  
on the RHS has an intersection type. The slight penalty of being long- 
winded in those situations is not as big as the potential for future  
pain, IMO.

Marek: I got it right. expressions in java routinely have intersection  
types. Just try to ascertain what the type is of:

'foo ? new LinkedList() : new ArrayList()'. It's Serializable &  
Cloneable & AbstractList<RAW>. Expressions have had such types since  
java 1.4 (1.5? - whichever one relaxed the ternary operator typing).  
The entire point of discussion here is: Do we extend this intersection  
concept to the type of *variables*? Currently only expressions and the  
bounds on generics parameters can be intersections.

Remi: Which problems do you see? Muchos gracias for a link to the  

  --Reinier Zwitserloot

On Mar 29, 2009, at 14:23, Florian Weimer wrote:

> * Reinier Zwitserloot:
>> final list = foo ? new LinkedList() : new ArrayList();
>> the type of 'list' is what, exactly?
> It's the type specified in section 15.25 of the JLS.  I can't find a
> definition of lub(T1, T2) in the spec, but "lub" probably stands for
> "least upper bound", and lub(LinkedList, ArrayList) would be
> AbstractList & Serializable & Cloneable (if I got the types right).
>> Serializable? Cloneable? List?  They're all valid, so that wouldn't
>> work.
> Intersection types are already part of the language, so I don't see
> any problem.  The following compiles:
>    interface I1 {}
>    interface I2 {}
>    static class C1 implements I1, I2 {}
>    static class C2 implements I1, I2 {}
>    static <T extends I1 & I2> void foo1(T foo) {
>    }
>    static void foo1(boolean foo) {
> 	foo1(foo ? new C1() : new C2());
>    }
> Existence of intersection types also leaks to the surface during
> overload resolution.
> It's just that you can't write down the type of some expressions using
> Java type notation.  For local variables, this isn't a problem; only
> debugging information needs to be updated slightly.  The effect for
> fields would be more pronounced, and I guess to stay within COIN's
> scope, a proposal would have to exclude inference for fields.

More information about the coin-dev mailing list