Re: No coercion in for-each loop?
Dave Stallard wrote:
List list = new ArrayList();
for (String s : list)
System.out.println(s);
It says "Type mismatch: Cannot convert from element type Object to
String". It's fine if I change decl of list to List<String>, or coerce
list to List<String> in the loop decl;
Since many people have already belabored the correct answer to death, I
will attempt to merely provide another avenue for your pondering.
(Definitions, etc., provided from JLS 3 ?14.14.2)
Outside the context of the arrays, the foreach loop boils down to this:
for ( VariableModifiers_opt Type Identifier: Expression)
The `Expression', if not an array, must be an object of type `Iterable'.
For Iterable types, the for statement becomes equivalent to this statement:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableModifiers_opt Type Identifier = #i.next();
// Rest of loop
}
where #i is a unique, unused identifier, and I is the type of
Expression.iterator(). So in your case, this is the transformed for loop:
for (Iterator #i = list.iterator(); #i.hasNext(); ) {
String s = #i.next();
System.out.println(s);
}
Since the return type of the raw Iterator.next() function is an Object,
you would have a compile-time cast exception in the transformed for
loop, and therefore you have one in the foreach loop.
The compiler doesn't mind the
code below, even though it causes a runtime type-cast error.
It does mind it: it throws an unchecked warning on the conversion
between list and ar, as required by JLS 3, ?5.1.9
> So why can't it insert the cast to String in the loop setup? Am I
> missing something?
From JLS 3, ?5.1.9:
Unchecked conversion is used to enable a smooth interoperation of legacy
code, written before the introduction of generic types, with libraries
that have undergone a conversion to use genericity (a process we call
generification).
[...]
While the conversion is unsound, it is tolerated as a concession to
practicality.
Without the generics, the compiler is forced to work off of the raw
return type of List's iterator method: Object. Since the conversion to
String cannot be verified.
Your setup uses inherently unsafe code to begin with: the compiler only
accepts it because to not do so would break too much code (hence the quote).
Since the introduction of foreach and generics go hand-in-hand, there is
no need to tolerate such unsound conversions.
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth