www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - for versus foreach

reply "Ameer Armaly" <ameer_armaly hotmail.com> writes:
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

What are the reasons/differences in using foreach over a for loop?  Is =
it just performance or readability?

--=20



Ameer
---
Visit my blog at
http://ameerarmaly.blogspot.com
---
Life is either tragedy or comedy.
 Usually it's your choice. You can whine or you can laugh.
--Animorphs
Apr 08 2006
next sibling parent Dave <Dave_member pathlink.com> writes:
Ameer Armaly wrote:
 What are the reasons/differences in using foreach over a for loop?  Is 
 it just performance or readability?
 

I've rarely seen it either increase or decrease performance by any significant degree in my benchmark code, but I suppose(?) future compilers could more easily optimize foreach loops to unroll and/or vectorize with SIMD because of the semantics of foreach loops (local key and value variables, array length is available, etc.). I find them easier to read and now more concise to write too since key/value inference was added. foreach should make it harder to overrun buffers (either unintentionally or as an attack on the service or binary) too because there is always a length component to D arrays. It won't prevent things like DOS attacks on buffers made of dynamic arrays, but foreach should generally make looping over D arrays safer and more secure if you can use it. - Dave
 -- 
  
  
 Ameer
 ---
 Visit my blog at
 http://ameerarmaly.blogspot.com
 ---
 Life is either tragedy or comedy.
  Usually it's your choice. You can whine or you can laugh.
 --Animorphs

Apr 08 2006
prev sibling next sibling parent Frank Benoit <benoit__ __tionex.de> writes:
Ameer Armaly schrieb:
 What are the reasons/differences in using foreach over a for loop?  Is
 it just performance or readability?
 

foreach * better readable * looping is allways the same. For arrays, linked lists etc. * the container itself controls the loop automagically.
Apr 08 2006
prev sibling next sibling parent reply kris <foo bar.com> writes:
Ameer Armaly wrote:
 What are the reasons/differences in using foreach over a for loop?  Is 
 it just performance or readability?

Both. Foreach is syntactically succinct, and can often produce better codegen than either integer-based or pointer-based for() loops ~ I did quite a bit of testing in this arena when writing high-throughput UTF converters, and was vaguely surprised by the subtle but noticable differences. This is perhaps most visible when iterating across arrays, where conventional wisdom might have favoured a pointer-based for() instead: int[] xx; foreach (x; xx) ... With the x86-32 architecture, anything that prevents register-spills is a bonus for some types of code, and I found foreach to be a better choice in a number of cases. The potentially negative aspect is that foreach is based upon a callback mechanism, so if the loop-body cannot be "inlined" there will be a call/ret involved for each iteration. Whether or not that's significant is very much application specific. From a syntactic perspective, you can get quite creative with foreach. Yet even the typical fare is quite elegant: foreach (record; table.iterator) { record.set ("fu", "bar"); ... record.update; } One syntactic benefit of for() loops is that one can declare and initialize control-vars within: for (int i=0, j=foo.length; i < j; ++i) ... Whereas foreach() tends to encapsulate such things within the opApply() design. Both approaches are very useful; foreach is perhaps the "more elegant" choice for many cases ~ perhaps the majority? The nice thing about foreach() is that the opApply() involved is encapsulated by the hosting class/struct ~ this has all the OOP benefits in terms of isolating implementation details that might otherwise have to be exposed at each traditional for() site. Yes, one can design in such a way that for() does something similar in terms of encapsulation; but it's not quite the same. For reference purposes, I think there's only a few for() loops within Mango, whereas there's lots of foreach() ~ the former are used, for example, to sweep backwards over an array; foreach doesn't currently handle that effectively.
Apr 08 2006
parent reply John Demme <me teqdruid.com> writes:
kris wrote:
 
 With the x86-32 architecture, anything that prevents register-spills is
 a bonus for some types of code, and I found foreach to be a better
 choice in a number of cases. The potentially negative aspect is that
 foreach is based upon a callback mechanism, so if the loop-body cannot
 be "inlined" there will be a call/ret involved for each iteration.
 Whether or not that's significant is very much application specific.
 

I don't think foreach can ever be inlined in the operator overloading case since opApply takes a delegate. DMD might be smarter than I though; however, I've refactored delegate parameters into templated code for the sole purpose of allowing functions to be inlined. ~John Demme
Apr 08 2006
parent kris <foo bar.com> writes:
John Demme wrote:
 kris wrote:
 
With the x86-32 architecture, anything that prevents register-spills is
a bonus for some types of code, and I found foreach to be a better
choice in a number of cases. The potentially negative aspect is that
foreach is based upon a callback mechanism, so if the loop-body cannot
be "inlined" there will be a call/ret involved for each iteration.
Whether or not that's significant is very much application specific.

I don't think foreach can ever be inlined in the operator overloading case since opApply takes a delegate. DMD might be smarter than I though; however, I've refactored delegate parameters into templated code for the sole purpose of allowing functions to be inlined. ~John Demme

Hmmm; I've almost forgotton the circumstances where I was seeing the call/ret being excised away ... ah, yes ~ it's when the foreach is used with native types (e.g. mango.convert.Unicode). Thus, there wasn't a call/ret present to begin with. Thanks for the prodding.
Apr 08 2006
prev sibling parent Walter Bright <newshound digitalmars.com> writes:
Ameer Armaly wrote:
 What are the reasons/differences in using foreach over a for loop?  Is 
 it just performance or readability?

By using foreach, you are letting the compiler decide on the optimization rather than worrying about it yourself. For example - are pointers or indices better? Should I cache the termination condition or not? Should I rotate the loop or not? The answers to these questions are not easy, and can vary from machine to machine. Like register assignment, let the compiler do the optimization. for (int i = 0; i < foo.length; i++) or: for (int i = 0; i < foo.length; ++i) or: for (T *p = &foo[0]; p < &foo[length]; p++) or: T *end = &foo[length]; for (T *p = &foo[0]; p < pend; ++p) or: T *end = &foo[length]; T *p = &foo[0]; if (p < pend) { do { ... } while (++p < end); } and, of course, should I use size_t or int? for (size_t i = 0; i < foo.length; i++) Let the compiler pick! foreach (v; foo) ... Note that we don't even need to know what the type T needs to be, thus avoiding bugs when T changes. I don't even have to know if foo is an array, or an associative array, or a struct, or a collection class. This will also avoid the common fencepost bug: for (int i = 0; i <= foo.length; i++) And it also avoids the need to manually create a temporary if foo is a function call. The only reason to use a for loop is if your loop does not fit in the conventional form, like if you want to go through the array backwards, or change the termination condition on the fly.
Apr 08 2006