Community
Participate
Working Groups
Build ID: I20080502-0100 Steps To Reproduce: Compile any source like: Source Code: ArrayList<ContingentDAO> contingentDAOs = new ArrayList<ContingentDAO>(); for (IContingentDAO contingentDAO : contingentDAOs) { Tested under Eclipse 3.3 and 3.4 and jdk 1.5 More information: Source Code: ArrayList<ContingentDAO> contingentDAOs = new ArrayList<ContingentDAO>(); for (IContingentDAO contingentDAO : contingentDAOs) { results in compiled code: Sun javac code: Iterator i$ = contingentDAOs.iterator(); do { if(!i$.hasNext()) break; IContingentDAO contingentDAO = (ContingentDAO)i$.next(); Eclipse compiler code: if(contingentDAOs.size() > 0) { for(Iterator iterator1 = contingentDAOs.iterator(); iterator1.hasNext();) { IContingentDAO contingentDAO = (IContingentDAO)iterator1.next(); as you see Sunn casts to the type given by the ArrayList and eclipse casts to the type given in the for (...)
Maxime - pls make some investigation if this would have been a recent change in javac. On such code, I am noticing strange behavior from javac: import java.util.*; public class X implements Runnable { public void run() {/**/} void foo() { List<X> runnables = new ArrayList<X>(); for (Runnable r : runnables) { r.run(); } Object o = runnables.get(0);//#1 X x = runnables.get(1);//#2 } } It doesn't insert a cast to Object for (#1), but it does for (#2). void foo(); 0 new ArrayList [2] 3 dup 4 invokespecial ArrayList() [3] 7 astore_1 8 aload_1 9 invokeinterface List.iterator() : Iterator [4] [nargs: 1] 14 astore_2 15 aload_2 16 invokeinterface Iterator.hasNext() : boolean [5] [nargs: 1] 21 ifeq 43 24 aload_2 25 invokeinterface Iterator.next() : Object [6] [nargs: 1] 30 checkcast X [7] 33 astore_3 34 aload_3 35 invokeinterface Runnable.run() : void [8] [nargs: 1] 40 goto 15 43 aload_1 44 iconst_0 45 invokeinterface List.get(int) : Object [9] [nargs: 2] 50 astore_2 51 aload_1 52 iconst_1 53 invokeinterface List.get(int) : Object [9] [nargs: 2] 58 checkcast X [7] 61 astore_3 62 return Our implementation does only insert the minimal cast required to match expectation. In these cases, no cast is needed for cast to Object, and for matching Runnable, no need to cast to X.
We do produce: void foo(); 0 new ArrayList [18] 3 dup 4 invokespecial ArrayList() [20] 7 astore_1 [runnables] 8 aload_1 [runnables] 9 invokeinterface List.iterator() : Iterator [21] [nargs: 1] 14 astore_3 15 goto 34 18 aload_3 19 invokeinterface Iterator.next() : Object [27] [nargs: 1] 24 checkcast Runnable [5] 27 astore_2 [r] 28 aload_2 [r] 29 invokeinterface Runnable.run() : void [33] [nargs: 1] 34 aload_3 35 invokeinterface Iterator.hasNext() : boolean [35] [nargs: 1] 40 ifne 18 43 aload_1 [runnables] 44 iconst_0 45 invokeinterface List.get(int) : Object [39] [nargs: 2] 50 pop 51 aload_1 [runnables] 52 iconst_1 53 invokeinterface List.get(int) : Object [39] [nargs: 2] 58 checkcast X [1] 61 pop 62 return
Oops - my previous testcase was wrong. Trying again. import java.util.*; public class X implements Runnable { public void run() {/**/} void foo() { List<X> runnables = new ArrayList<X>(); for (Runnable r : runnables) { r.run(); } Object o = runnables.get(0); Runnable r = runnables.get(1); } } JAVAC (1.6.0_10-beta) produces: void foo(); 0 new ArrayList [2] 3 dup 4 invokespecial ArrayList() [3] 7 astore_1 8 aload_1 9 invokeinterface List.iterator() : Iterator [4] [nargs: 1] 14 astore_2 15 aload_2 16 invokeinterface Iterator.hasNext() : boolean [5] [nargs: 1] 21 ifeq 43 24 aload_2 25 invokeinterface Iterator.next() : Object [6] [nargs: 1] 30 checkcast X [7] 33 astore_3 34 aload_3 35 invokeinterface Runnable.run() : void [8] [nargs: 1] 40 goto 15 43 aload_1 44 iconst_0 45 invokeinterface List.get(int) : Object [9] [nargs: 2] 50 astore_2 51 aload_1 52 iconst_1 53 invokeinterface List.get(int) : Object [9] [nargs: 2] 58 checkcast Runnable [10] 61 astore_3 62 return where ECJ 3.4RC1 produces: void foo(); 0 new ArrayList [18] 3 dup 4 invokespecial ArrayList() [20] 7 astore_1 [runnables] 8 aload_1 [runnables] 9 invokeinterface List.iterator() : Iterator [21] [nargs: 1] 14 astore_3 15 goto 34 18 aload_3 19 invokeinterface Iterator.next() : Object [27] [nargs: 1] 24 checkcast Runnable [5] 27 astore_2 [r] 28 aload_2 [r] 29 invokeinterface Runnable.run() : void [33] [nargs: 1] 34 aload_3 35 invokeinterface Iterator.hasNext() : boolean [35] [nargs: 1] 40 ifne 18 43 aload_1 [runnables] 44 iconst_0 45 invokeinterface List.get(int) : Object [39] [nargs: 2] 50 pop 51 aload_1 [runnables] 52 iconst_1 53 invokeinterface List.get(int) : Object [39] [nargs: 2] 58 checkcast Runnable [5] 61 pop 62 return i.e. we agree except for the foreach loop. I could only explain the difference by the fact Javac misses the assignment conversion in for the current element in iteration !? i.e. their bug !
I believe our behavior is the right one. Closing as Javac bug. Hence marking as invalid. Added GenericTypeTest#test1332
Could find no matching javac bug (which is not that surprising given the fact that both strategies lead to runnable code). While the runtime behavior tolerates some interpretation, the specification puts more constraints on what should be done. The following test case leverages the definition of the foreach loop in the spec: import java.util.ArrayList; import java.util.Iterator; import java.util.List; public abstract class X { public static void main(String... args) { List<Y> elements = new ArrayList<Y>(); // foreach loop for (I element: elements) { element.foo(); } // translation of the foreach loop according to JLS 3 ยง 14.14.2 for (Iterator<Y> i = elements.iterator(); i.hasNext(); ) { I element = i.next(); element.foo(); } } } interface I { void foo(); } class Y implements I { public void foo() { } void bar() { } } Looking at the generated code, we are doing the same cast in both cases, while javac generates a cast to Y in the first loop, hence generating different code for two sources fragments deemed equivalent by the spec. While we will leave javac's people decide for themselves whether they have a bug or not, the equivalence argument proves our conforming to the spec.
Verified for 3.4 RC2 using build I20080523-0100. (Checked that the byte code of comment #5 still had the expected characteristics.)
This must be a duplicate of bug 209779 indeed, which led to the same conclusions by a similar path. Following links from there, found out that javac bug has been identified since as http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500701.