Proposal: Accepting a subclass as an element type in a for loop

Jean-Louis Ardoint jlardoint at ilog.fr
Tue Mar 31 08:41:20 PDT 2009


You might say that all proposals are very niche, and almost all of them can be solved by writing some code (you may save some time by writing a generic comment ☺).

About 
List<Set<Number>> foo = someMethodCall();
for ( Set<Double> set : foo ) {
   // You can't do this in java.
}

I don't understand your point. A List<Set<Number>> should not contain a Set<Double> if you use generics without tweaks. So what would you expect?

Anyway, thank you for your comments.

--Jean-Louis Ardoint



________________________________________
From: Reinier Zwitserloot [mailto:reinierz at gmail.com] On Behalf Of Reinier Zwitserloot
Sent: Tuesday, March 31, 2009 5:16 PM
To: Jean-Louis Ardoint
Cc: coin-dev at openjdk.java.net
Subject: Re: Proposal: Accepting a subclass as an element type in a for loop

Why is this worthy of a language change? It's very niche.

You can solve your problem by writing 1 method, like so:

for ( Rectangle r : MyUtilityClass.filterOnType(shapes, Rectangle.class) ) {
   drawRectangle(r);
}


with:

public class MyUtilityClass {
    public static <A, B> List<B> filterOnType(Iterable<? extends A> in, Class<B> outType) {
        List<B> list = new ArrayList<B>();
        for ( A a : in )
            if ( outType.isInstance(a) ) list.add(outType.cast(a));
        return list;
}



Even if you disregard for a moment that if you add this, I've got about a gazillion other niche things that have about as many use cases and are about as easy to solve with a library for coin,your proposal has omitted a rather serious issue:

What would you do if you have something like:

List<Set<Number>> foo = someMethodCall();
for ( Set<Double> set : foo ) {
   // You can't do this in java.
}



 --Reinier Zwitserloot



On Mar 31, 2009, at 14:55, Jean-Louis Ardoint wrote:


I'm maybe a bit too late. Here's my proposal anyway.



-- Jean-Louis Ardoint



Accepting a subclass as an element type in a for loop



AUTHOR(S): Jean-Louis Ardoint



OVERVIEW



FEATURE SUMMARY



Add a filtering and downcast capability to the enhanced for statement
(a.k.a for each).



MAJOR ADVANTAGE



It should reduce the number of lines of code and depth of nesting in
loops. The resulting code would be more readable that what is done
currently to achieve the same goal. The meaning of such a loop is quite
obvious.



MAJOR BENEFIT



Better readability and expressiveness.



MAJOR DISADVANTAGE



More complexity in the compiler to generate a little bit more bytecode.



ALTERNATIVE



You can currently the same thing, yet it means adding an extra if
statement and an intermediate variable to be cast.



EXAMPLES



Here is a small not very interesting example of such a enhanced for
loop:



Shape[] shapes = ...;

for (Shape s : shapes)

     drawShape(s);



If for a reason you would need to draw only the rectangles, you would
need to write:



for (Shape s : shapes) {

 if (s instanceof Rectangle)

   drawRectangle((Rectangle)s);

}



This is not very aesthetic. If only the for loop would directly accept a
subclass as the element type and do the type checking and downcast, we
could be able to write:



for (Rectangle r : shapes)

 drawRectangle(r);



Note that there is a subtlety w.r.t. the handling of nulls. See
Compilation below for more details



DETAILS



SPECIFICATION:



The grammar is unchanged. The equivalence between an enhanced for loop
and a regular for loop has to be changed in JLS 14.14.2.

COMPILATION:



The way enhanced loop are translated into bytecode would change
depending on whether the loop variable type is a subclass of the
iterable or array element type.

If the loop variable type is a subclass, then the loop is equivalent to:



For an expression returning Iterable<C>:

Iterable<C> cs...

for (I #i = cs.iterator(); #i.hasNext(); ) {

 C #c = #i.next();

 if (#c == null || #c instanceof D) {

   D d = (C)#c;

   ... 

 }

}



For an array:



C[] ca...

for (int i = 0; i < ca.length; i++) {

 C #c = ca[i];

 if (#c == null || #c instanceof D) {

   D d = (C)#c;

   ... 

 }

}



Note that we need to test against null to keep the same behavior as the
regular enhanced for loop.



TESTING:



This feature can be tested in the same way the enhanced for loop is
tested.





LIBRARY SUPPORT:



There is no need for library support.





REFLECTIVE APIS:



No updates to the reflection APIs are needed.





OTHER CHANGES:



No other changes are needed.





MIGRATION:



Migration of existing enhanced for loop can be done if one desires so.



COMPATIBILITY





BREAKING CHANGES:



This feature would not break any existing programs, since the new
feature only permits more code to be parsed than before.





EXISTING PROGRAMS:



Class file format does not change, so existing programs can use class
files compiled with the new feature without problems.
















More information about the coin-dev mailing list