Enumerating over arrays with for vs. foreach


Brad Abrams forwarded an interesting question to me this morning


 


Questions:


What is the difference between enumerating an array using for versus foreach ?


What is the recommended practice and why?


 

I did a quick analysis for him which he has just posted in full.  Have a look see.

Comments (12)

  1. Slavo Furman says:

    Rico, and what do you say about Joshua Allen’s similar analysis on using loops?

    "Loopy Decisions"

    (http://www.netcrucible.com/blog/PermaLink.aspx?guid=1becbd8e-5b9f-40f0-bddf-994aeb580028)

    thanks,

    Slavo.

  2. Rico Mariani says:

    Well basically he’s saying the exact same thing as me. There’s no difference between the first two cases and in any case there isn’t ever likely to be enough difference that you should change your coding style.

    But the most important thing he says is that, whatever you do, if you’re going to make a change like this, do measure it in your own scenarios to see what you’d be getting. Who knows, maybe in a more complex function the optimizer will have a heart-attack and not be able to reduce the code down properly.

    For my part, I just would like to remind you that this is all about arrays and not ArrayLists or other collection classes.

    Quoteing from my other message:

    See the "Enumeration Overhead" section in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp — searching for "foreach" in that same document will give other illustrations and guidance.

  3. nfactorial says:

    Hi Rico,

    A question related to this has been occuring to me also. Whilst the above makes much sense, enumerating an array occurs far less frequently than enumerating a [custom] collection. When I say custom collection, I mean a total, type-safe collection (rather than one being a simple wrapper around ArrayList or something).

    Ie. The data members of such a collection may look similar to:

    private const int DefaultCapacity = 16;

    private int count = 0;

    private Item[] itemList;

    Where itemList expands to reach contain items as they are added. This means that count will never exceed itemList.Length. However, I would guess that the JIT wont be clever enough to reach this conclusion and thus add the bounds checking. Even when an index is made on the collection:

    public Item this[ int index ]

    {

    get

    {

    if ( index < 0 || index >= count )

    throw new IndexOutOfRange…

    return itemList[ index ];

    }

    }

    I already put a bounds check here obviously, but because I’m using ‘count’ instead of ‘itemList.Length’ would there be another one added by the JIT? Of course I could look at the debug output, and I will if it becomes a problem for me (at the moment, I’m just interested to see if it may be an issue ๐Ÿ™‚

    Also, if the above does pose a problem for the JIT, is this still applicable when using generic collection in Whidbey. Or is the JIT more intellegent with them (I don’t have access to Whidbey atm)?

    I’m more interested in the foreach case in custom collections, as I generally use foreach in this case rather than iterating over them using for.

    Thanks,

    n!

  4. Rico Mariani says:

    The jit wouldn’t have any way of knowing that your "count" is strictly less than the array length in all cases so yes I’d expect you to incur a second test until maybe some day when we could do some very deep analysis and still jit fast enough.

    You could remove the index < 0 test if you’re willing to throw the array bounds check exception instead.

    Depending on your use of the collection it may or may not make a difference. I’d expect most times it wouldn’t end up mattering much. Usage is everything.

  5. Rico Mariani says:

    By the way, what you have looks remarkably like System.ArrayList I was wondering why you didn’t just use that?

  6. nfactorial says:

    Thanks for the notes! I thought it’d be too much for the JIT but just wondered if I was underestimating it ๐Ÿ™‚

    As for not using ArrayList, it was only an example ๐Ÿ™‚ But I usually write the above for value type collections to avoid the boxing penalty of System.ArrayList. As I said, no whidbeygenerics as of yet ๐Ÿ™

    Thanks again,

    n!

  7. nfactorial says:

    Hi again,

    Sorry to come back to this ๐Ÿ™‚ I was thinking, is it possible to provide a hint to the JIT that a local count *is* in actual fact less than the length of the array. Thus avoiding the bounds check each time.

    For instance, if I have a custom collection and within a collection method I need to scan the array:

    public class MyCollection

    {

    private int count = 0;

    private int[] itemList;

    … yadda yadda …

    public bool Contains( int someValue )

    {

    for ( int loop = 0; loop < count; ++loop )

    {

    if ( itemList[ loop ] == someValue )

    return true;

    }

    return false;

    }

    }

    I will get the bounds check, would the JIT understand something like:

    public bool Contains( int someValue )

    {

    if ( count > 0 && count <= itemList.Length )

    {

    for ( int loop = 0; loop < count; ++loop )

    {

    if ( itemList[ loop ] == someValue )

    return true;

    }

    }

    return false;

    }

    Although the first ‘if’ statement essentially does nothing (I know count is within this range), would the JIT take the hint? Again, please ignore the uselessness of this example ๐Ÿ™‚

    I’m thinking it doesn’t (would be nice if it did), but could well be wrong ๐Ÿ™‚

    Thanks,

    n!

  8. Brad Abrams says:
  9. I think it’s same thing below.

    Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

    for (int i=0; i<assemblies.Length; i++)

    DoSomething(assemblies[i]);

    foreach (Assembly a in assemblies)

    DoSomething(a);

Skip to main content