Type inference
Hi,
We all know, that:
List<Integer> li=new ArrayList<Integer>();
List<?> l=li;
l.add(1);
won't compile. The main reason for that is that at runtime we lose
all the type information, so compiler can't be sure, whether it can
safely add some object to a list. Because <?> stands for all the types,
it would be safe to:
l.add("Text");
In runtime however, it would throw the ClassCastException if someone
would retrieve the object from the list:
Integer i=l.get(0);//let's forget for a while that in that case l.get(0) returns an
// Object - not an Integer ...
So to prevent it, compiler doesn't allow it (for the same reason
List<Object> l=new ArrayList<Integer> is not allowed).
Another thing, which could be worked around by the compiler, is the
fact that we have:
List<E>{
add(E e);
}
, so if we use List<?>, how does the add method signature look like ?
add(? e) ?. Therefore all methods with the type parameter in the signature
are not allowed to be invoked on any reference variables with wildcards associated
with it (even when the method might have an empty body).
My question is:
Why is compiler not smart enough to deduce that:
List<Integer> li=new ArrayList<Integer>();
List<?> l=li;
l.add(1);
l stands for List<Integer> ? It could had a look at li and see that
it is List<Integer> thus treating l the same way ... Was it really so
difficult to implement it ? I understand, that it would had to log all
the uses of that kind, so every possible assignment to l would have
to be resolved to a proper parameterized type, eg:
List<Integer> li=new ArrayList<Integer>();
List<?> l=li;// ok
l.add(1);// would be ok;
l.add("text");// it would raise error
List<String> ls-new ArrayList<String>();
l=ls;// ok
l.add("text");// now it is ok
l.add(1);// and now this would raise error
Any comments on that ?
Cheers,
Adrian
# 1
> The main reason for that is that at runtime we lose
> all the type information, so compiler can't be sure,
> whether it can safely add some object to a list.
No, the reason in this case is that the compiler doesn't know the element type is Integer so it won't autobox the int '1' into an Integer, and List<?> means List of Object, and an 'int' isn't an object, so List<?>.add(int) doesn't compile.
ejpa at 2007-7-12 10:08:55 >

# 2
>
> No, the reason in this case is that the compiler
> doesn't know the element type is Integer so it won't
> autobox the int '1' into an Integer, and List<?>
> means List of Object, and an 'int' isn't an object,
> so List<?>.add(int) doesn't compile.
No, this is not the reason. Adrian's initial explanation was closer to the truth.
First of all, List<?> does not mean "List of Object". It means "typesafe List of an unknown element type". This is a fundamental difference. And second of all, if it really were "List of Object", there would be no autoboxing problem at all. The compiler autoboxes the "1" into an Integer and then passes it to any method that expects an Object. Try it!
# 3
> Was it really so
> difficult to implement it ?
What makes you think that the development team tried to do this?
> I understand, that it
> would had to log all
> the uses of that kind, so every possible assignment
> to l would have
> to be resolved to a proper parameterized type, eg:
>
> List<Integer> li=new ArrayList<Integer>();
> List<?> l=li; // ok
> l.add(1);// would be ok;
> l.add("text");// it would raise error
> List<String> ls-new ArrayList<String>();
> l=ls; // ok
> l.add("text");// now it is ok
> l.add(1);// and now this would raise error
>
> Any comments on that ?
Let's assume for a moment that there is no technical barrier to doing this. What benefit would be gained that would warrant this effort? Is the only benefit that you would be able to reuse the same variable for different parameterized types?