The Bum Rap of foreach


Update: fixed the title per comments and I noticed Rico chimed in.


 


 


I had two separate interactions today where someone told me they opted for ugly\error prone for-loop code because foreach was “too slow”.  There are so many things wrong with that analysis where do I start??


 



  1. In one of the cases we were iterating over an array… Google helped me quickly find this post and Kevin is right, C# and VB make foreach of arrays just peachy. 
  2. The rationale for why foreach is “too slow” was simply “Rico said so”.  Again a quick google search puts the direct facts to rest.  But the meta-issue, which I am sure Rico would agree with, is that there are very few “laws” of perf.  Know your scenarios and measures are the only two I think.  Because rico said didn’t work for me in 2nd grade and it doesn’t work for you now either.
  3. Yes, fine there is something to be aware of wrt foreach over ArrayList, which I will not repeat here but to say they very often are a wash in real world scenarios and developer productivity (on-time, less bugs) is almost always a better tradeoff.  In addition, you can mitigate this in your own collection types today and we have addressed it with List<T> in Whidbey.  
  4. It is my belief most of our customers are not having significant perf issues on the platform (but I am always open to new data).  That is not to say the CLR doesn’t have some perf issue we need to address (we do!), I am just saying that on balance, for the kinds of apps customers are building today the value we give far outweighs the cost.  Where there are perf issues, I seriously doubt they are fixed by moving from foreach to for!
  5. Eric tells me Java is adding foreach because it is such a useful feature… it can’t be that bad 😉


 


Go, use foreach and be proud!

Comments (13)

  1. Morton says:

    I just wish I could always use foreach, even when making changes inside it which are currently not possible. But guess there’s no general way of handling what should happen. BTW could tracepoints be used to somehow time how much time is spent in particular method or whatever? I’ve tried use clr profiler, but for sunday programmer who comes from scripting background, it can be quite effort trying to pinpoint where is most of the time spent, incase there isn’t anything very obvious visible. (Like program could be stalling at waiting for DNS due to some bad design or whatever)

  2. Steve says:

    Call me old hat, but I prefer using the old for approach. There’s no specific reason regarding performance, just a preference.

  3. ChadThiele says:

    I always use foreach. Ugh, if I can get away from using the for loop, good riddence! I like the cleaner code of foreach. Of course, for can do some things foreach can’t, so it has to be used sometimes… but I do prefer foreach whenevr possible.

  4. um…while I agree that foreach is a good thing and use it often, I wouldn’t say that a for is inherently ugly or error prone…just because some programmers aren’t’ able to avoid fencepost errors doesn’t mean we all are…and sometimes you just need an interator variable, especially when looping collections that don’t support foreach..

  5. damien morton says:

    Not wanting to be pedantic, but….

    Its Bum Rap, not Bum Wrap 🙂

    And for all those that think this is a Mute Point, it is in fact a Moot Point.

  6. marklio says:

    foreach rocks! especially because of the behavior injection we can add in by implementing our own Enumerator classes that enable us to "foreach" over trees and other non-linear structures that would require nasty for loops or some other custom looping mechanism otherwise. Iterators in C# 2.0 will make foreach even more powerful. Can’t wait to actually get to use them!

  7. Doug McClean says:

    foreach is great! I just wish I could foreach over IEnumerators as welll as IEnumerables, for collections that can be enumerated in multiple orderings.

  8. Jeffrey Sax says:

    As mentioned earlier, the best thing about foreach is that you can isolate iteration code, especially where an iteration is cheaper than indexed access. One thing I find unfortunate is that foreach allows you to iterate over only one collection. What if you want to iterate over two (or more) collections in parallel?

    foreach(a in colA, b in colB) { /* Do something with a and b */ }

    I can think of many scenarios where this is useful, and it is consistent with the capabilities of ‘classic’ for loops.

  9. damien morton says:

    In Python, parralel iteration is done with tuples and the zip() function.

    for (a,b) in zip(colA, colB):

    dosomething(a, b)

    zip() is like the "dot product" of two sequences.

    If it were possible to define operators on interfaces, we could have something like:

    IEnumerable<Pair<A,B>> operator*(IEnumerable<A> a, IEnumerable<B> b)

    {

    IEnumerator<A> ae = a.GetEnumerator();

    IEnumerator<B> be = b.GetEnumerator();

    while (ae.MoveNext() && be.MoveNext())

    {

    yield return new Pair<A,B>(ae.Current, be.Current);

    }

    }

    public class Pair<A, B>

    {

    public readonly A first;

    public readonly B second;

    public Pair(A a, B b)

    {

    this.first = a;

    this.second = b;

    }

    }

    List<int> x = new List<int>();

    List<int> y = new List<int>();

    for (int i = 0; i < 10; i++)

    {

    x.Add(i);

    y.Add(i * i);

    }

    foreach (Pair<int,int> p in x*y)

    Console.WriteLine(p.first + "," + p.second);

    ahh, but it would nice…

  10. In early MSDN show about performance in CLR, folks showed that for is faster than foreach (they also cache the length before the loop). In most cases I use foreach. People from CLR/C# team in Microsoft now tell that foreach is optimized, so need to recheck that MSDN show.

  11. Stuart Celarier says:

    Demian, no it is not "bum wrap", it is "bum rap". See http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va=rap, definition 2b. When correcting someone, it lends credibility to be, in fact, correct.