Notes on implementing concise calls to constructors with type parameters
Reinier Zwitserloot
reinier at zwitserloot.com
Wed May 13 17:28:02 PDT 2009
Here's a crazy idea:
Why don't we deprecate raw types for constructors?
I know what you're saying: Deprecate stuff? in the core? we don't do
that in java land!
But I think it'll work out fine. All this means is:
A constructor call with no generics information, on a type where
generics information is expected, is no longer the raw type. It is the
'infer me please' type, entirely analogous to the diamond notation.
Here's the trick, though: This inference system can infer 'raw', no
problem. The following code:
List foo = new ArrayList();
has a raw List on the LHS (no changes in the type system, just
constructor calls), and thus the RHS would infer to new
ArrayList<RAW>().
The following:
List<String> foo = new ArrayList();
currently results in a raw list on the RHS, then raw-to-generified
conversion (which gives you a warning) to make the ArrayList<RAW> fit
in the required List<String> type. After this change, this would work
differently: the RHS is now ArrayList with the notion that the
generics need to be inferred, just like they would for static methods.
In this case, String is inferred, and the warning goes away.
This boils down to:
- no code that used to compile fine will now compile with errors or
warnings.
- warnings that used to exist will either still exist, or go away,
or become a different warning.
It's not 100% backwards compatible though, there's this one extremely
rare case where you run into trouble. Behold this monstrosity:
import java.util.List;
import java.util.ArrayList;
public class Foo {
public static void overloaded(Object x) {
System.out.println("overloaded(Object) called.");
}
public static void overloaded(Number x) {
System.out.println("overloaded(Number) called.");
}
public static void main(String[] args) {
overloaded(getList().get(0));
overloaded(new TestList().get(0));
}
//these methods are ugly but that's because they are
contrived use cases.
@SuppressWarnings("unchecked")
public static <T extends Number> List<T> getList() {
List x = new ArrayList();
x.add(1);
return x;
}
@SuppressWarnings("unchecked")
public static class TestList<T extends Number> extends ArrayList<T> {{
List x = this;
x.add(1);
}}
}
The raw type of TestList will end up calling the Object version, but
the generics inference of the static method infers Number, due to the
type bound.
Showstopper? No problem. Just add a rule that says: If the constructor
expression is used in a place where the inference engine cannot make
an unambiguous decision, instead of inferring the lower bound of the
generics parameter (the Foo in extends Foo), always infer Object.
I find the empty diamond notation very ugly; feels like a hack just to
ensure backwards compatibility. I think we can do better.
--Reinier Zwitserloot
On May 13, 2009, at 19:58, Ulf Zibis wrote:
> BTW 1 question:
>
> Is there any difference in writing:
> List<String> l = new ArrayList();
> or:
> List<String> l = new ArrayList<String>();
>
> I guess not, so why using 2nd writing.
>
> thanks,
>
> Ulf
>
>
>
More information about the coin-dev
mailing list