For vs. For Each

G

Guest

Is there a performance difference between this:

\\\
Dim i As Integer
For i = 0 to myObject.Controls.Count - 1
myObject.Controls(i) = ...
Next
///

and this:

\\\
Dim ctl As Control
For Each ctl In myObject.Controls
ctl = ...
Next
///

Or is For Each just "prettier"?

Thanks,

Eric
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

This was discussed a time ago and U think remember that there were almost
no differences,
beside that, this is VERY EASY to check just write an small program and
iterate both ways and see the results

and finally this is a VB.net question, not a C# one, there is no need to
post it on microsoft.public.dotnet.languages.csharp

cheers,
 
O

One Handed Man \( OHM - Terry Burns \)

There should be very little in the way of performance difference in these
two code snippets, especially as your control numbers are not likely to be
large anyway.

One point to note is that with For Each, you cannot remove the items or add
to the collection while iterating otherwise it complains, however with a for
loop, you can iterate backwards and remove items.




--

OHM ( Terry Burns )
. . . One-Handed-Man . . .
If U Need My Email ,Ask Me

Time flies when you don't know what you're doing
 
G

Gabriele G. Ponti

Anders Hejlsberg: "Generally my answer is, Always use FOR EACH if you can,
because chances are you will have fewer bugs if you use FOR EACH. There are
just more pitfalls with the regular FOR statement. It is true that in some
cases the FOR statement is more efficient. I think the vast majority of
cases, I don’t think you would ever notice. My advice would be, always use
FOR EACH profile your app. If they turn out to be your problem, then change
them to FOR statements, but I don’t think you ever will in real code. I
think FOR EACH is much more expressive, and in theory allows us to optimize
your code more in the future. There are certain optimizations that we will
do, because we can tell that you’re going over the entire collection or
whatever, and so we could, at least in theory, generate even better code. I
would highly recommend FOR EACH unless you really do need the index."

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624csharpah/manifest.xml
 
J

Jay B. Harlow [MVP - Outlook]

Eric,
In addition to the other comments:

Are you asking about the Controls collection specifically or are you asking
any collection in general?

As each collection type has its own performance characteristics!
(ControlCollection, verses ArrayList, verses Collection, verses an Array,
verses HashTable, verses insert your favorite collection here).

I have to ask: Does it really matter which is faster?

I would not worry about which performs better, I would go with which one is
more straight forward, I find the For Each more straight forward, so that is
the one I favor.

Remember that most programs follow the 80/20 rule (link below) that is 80%
of the execution time of your program is spent in 20% of your code. I will
optimize (worry about performance) the 20% once that 20% has been identified
& proven to be a performance problem via profiling (CLR Profiler is one
profiling tool).

For info on the 80/20 rule & optimizing only the 20% see Martin Fowler's
article "Yet Another Optimization Article" at
http://martinfowler.com/ieeeSoftware/yetOptimization.pdf

Hope this helps
Jay
 
N

Nick Malik

Would you have been happier if Eric has written the question in C#? This is
very much as important a question in C# as it is in VB.NET.

foreach (Control ctl in myObject.Controls)
{
// do something useful with 'ctl'

}

I've had folks tell me that 'for' is more efficient than 'foreach' because
of enumerator overhead. For most of my code, however, this is a moot point.
Unless the code is in a critical loop, the difference in processing so tiny
that the improvement in code readability greatly outweighs the overhead of
allowing .NET to manipulate the enumerator.

--- Nick

"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote
in message
 
C

Cowboy \(Gregory A. Beamer\) [MVP]

The For will beat For Each in sheer performance, due to the overhead of the
enumerator. But, life is not just about performance and the number of cycles
you are saving are unlikely to affect your application, unless you are
running close to scale.

I would do which ever feels most comfortable to you, for maintainability,
rather than tweak out every cycle you can. In all likelihood, the difference
is in the nature of micro-seconds.

--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

************************************************
Think Outside the Box!
************************************************
 
Y

Your_name

Anders Hejlsberg: "Generally my answer is, Always use FOR EACH if you
can, because chances are you will have fewer bugs if you use FOR EACH.
There are just more pitfalls with the regular FOR statement. It is
true that in some cases the FOR statement is more efficient. I think
the vast majority of cases, I don’t think you would ever notice. My
advice would be, always use FOR EACH profile your app. If they turn
out to be your problem, then change them to FOR statements, but I
don’t think you ever will in real code. I think FOR EACH is much more
expressive, and in theory allows us to optimize your code more in the
future. There are certain optimizations that we will do, because we
can tell that you’re going over the entire collection or whatever, and
so we could, at least in theory, generate even better code. I would
highly recommend FOR EACH unless you really do need the index."

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040624c
sharpah/manifest.xml

The big man has spoken, end of discussion :D
 
C

Cablewizard

In case you are interested in actual test results...

A while ago I tested a large number of scenarios to try to gauge performance
difference. Tried Collections and Arrays of both Objects and Structures with and
without collection Keys. My anticipated results were that Arrays would be faster
with Indexes and Collections faster with For Each. While this did sort of hold
true, actual results were MUCH less conclusive than I expected. Turns out
results depend a great deal on the underlying data types, size of underlying
data, quantity of items, etc. Additionally, the various collection types have
significantly different performance characteristics as well, again based on
usage.

Situations occured in each scenario where one or two methods were actually much
faster than the others. Sometimes one method was faster on the early items but
got slower in the later items, while another was consistently slower, but in the
end due to the volume of items ended up being much faster overall. So it is VERY
possible that if you tune your code to get the best performance with a
particular test data set, then you may very well create a situation where it
performs very poorly with other data sets.

So bottom line is as others have suggested.
If you don't need to explicitly reference particular items or need the results
in any particular order, then always use For Each.
Only if you need to add/remove items or are working specifically with Arrays of
value types should you use For Index.

Additionally, if you are working with collections, especially home grown
strongly typed collections, if you need more performance or special behaviour,
you can create your own enumerator to optimize performance.

As Jay pointed out, consider the 80/20 rule. Although due to the nature of
loops, they oftentimes fall into the 20 percent of code that consumes 80 percent
of the time. However, just go with the For Each and only worry about performance
if it becomes a problem.

Finally, go with Gabriele's suggestion, as he would know best ;-)

Gerald
 
A

Alvin Bruney [MVP]

I'll chime in here with my longtime gripe.

The foreach implementation is flawed because the container is marked as
readonly during the iteration. This is a crime in my opinion because it is
*normal to effect a change on the container while iterating especially from
a vb point of view.

The work around is impossibly difficult as well especially for beggining to
intermediate developers. Probably the cleanest approach is to use Eric
Gunnerson's iterative container assembly which sits between your application
and the iterated container. The least pleasing approach is to use a try
catch block and swallow the exception. If it takes Eric Gu to impliment a
special strategy to handle this case, it makes my point rather loudly.

This points to a huge flaw in the design and implementation of the foreach
construct. I don't see these guys on trial for that crime so i am
dissapointed.
 
G

Guest

Jay said:
Are you asking about the Controls collection specifically or are you asking
any collection in general?
As each collection type has its own performance characteristics!

I just meant collections in general, but you make a good point.
I have to ask: Does it really matter which is faster?

Not on my current projects, but it's good to know for the future.
Remember that most programs follow the 80/20 rule (link below) that is 80%
of the execution time of your program is spent in 20% of your code. I will
optimize (worry about performance) the 20% once that 20% has been identified
& proven to be a performance problem via profiling (CLR Profiler is one
profiling tool).

I usually follow the 80/20/100 rule, where I optimize the 20% and give the
remaining 80% a good work over anyway to make sure the aggregate is as
efficient as possible. ;-)

Thanks for your reply, Jay.

Eric
 
G

Guest

Thanks for the post, Nick.

Nick said:
I've had folks tell me that 'for' is more efficient than 'foreach' because
of enumerator overhead.

A newbie question...Where do enumerators come into play when using For Each?
In addition , since enumerators can only be of type byte, short, int, or
long, what kind of overhead is introduced?

Thanks again,

Eric
 
O

One Handed Man \( OHM - Terry Burns \)

He is referring to the Enumerator Interface IEnumerator. See below, you can
create your own.

Public Class Class1
Implements IEnumerator

Public ReadOnly Property Current() As Object Implements
System.Collections.IEnumerator.Current
Get

End Get
End Property

Public Function MoveNext() As Boolean Implements
System.Collections.IEnumerator.MoveNext

End Function

Public Sub Reset() Implements System.Collections.IEnumerator.Reset

End Sub
End Class

--

OHM ( Terry Burns )
. . . One-Handed-Man . . .
If U Need My Email ,Ask Me

Time flies when you don't know what you're doing
 
M

mikeb

Thanks for the post, Nick.




A newbie question...Where do enumerators come into play when using For Each?
In addition , since enumerators can only be of type byte, short, int, or
long, what kind of overhead is introduced?

By 'enumerators' Nick was referring to the IEnumerator interface which
is used by the For Each statement to iterate through the collection (For
Each uses and IEnumerable interface to get the IEnumerator).

I think you're confusing the terminology with an enumeration, such as
declared by VB.NET's Enum statement. A completely different animal.
 
G

Guest

mikeb said:
I think you're confusing the terminology with an enumeration, such as
declared by VB.NET's Enum statement. A completely different animal.

That's exactly what I was doing. Thank you for the clarification, Mike &
Terry.

Eric
 
J

JohnLiu

I disagree that foreach-construct being readonly is a bad thing. Not
to completely disregard Alvin's gripe, but here's my point of view.

Typically, you use foreach to iterate throught the collection.
Adding/Removing items from the collection during this time puts the
collection into a funny mode that others may not be ready to deal
with, what if you have multiple emunerators? (this is very common for
a nested foreach scenario, yes, that'd be O(n^2) ). I believe in C++
STL libraries you can remove current iterated item, but that opens a
can of worms, you always have to worry whether your current item has
been deleted by another thread.

Also, I highly disagree that the for-construct is faster than
foreach-construct. That is only true when you are talking about ARRAY
collection types. In a linked-list implementation, foreach-construct
O(1) would be faster than for-construct O(n) for iterating through a
collection. The fact that the .NET framework collections are almost
solely based on array types may make the statement correct in 90%+ of
the time, but it is not a correct statement to make generally. And,
besides, I wait for generics!

Typically, hashtables are iterated for the entire key/value pairs,
given that accessing the value of a hashtable is O(1), if you need to
iterate through a hastable, it's easier to iterate through the keys
O(n), and grabbing the value as you go O(1). But I can't think of why
anyone would be iterating through a hashtable except may be as a debug
step to see the contents of the hashtable.

jliu - www.ssw.com.au - johnliu.net
 
G

Guest

JohnLiu said:
I disagree that foreach-construct being readonly is a bad thing. Not
to completely disregard Alvin's gripe, but here's my point of view.

Typically, you use foreach to iterate throught the collection.
Adding/Removing items from the collection during this time puts the
collection into a funny mode that others may not be ready to deal
with, what if you have multiple emunerators? (this is very common for
a nested foreach scenario, yes, that'd be O(n^2) ). I believe in C++
STL libraries you can remove current iterated item, but that opens a
can of worms, you always have to worry whether your current item has
been deleted by another thread.

Also, I highly disagree that the for-construct is faster than
foreach-construct. That is only true when you are talking about ARRAY
collection types. In a linked-list implementation, foreach-construct
O(1) would be faster than for-construct O(n) for iterating through a
collection. The fact that the .NET framework collections are almost
solely based on array types may make the statement correct in 90%+ of
the time, but it is not a correct statement to make generally. And,
besides, I wait for generics!

Typically, hashtables are iterated for the entire key/value pairs,
given that accessing the value of a hashtable is O(1), if you need to
iterate through a hastable, it's easier to iterate through the keys
O(n), and grabbing the value as you go O(1). But I can't think of why
anyone would be iterating through a hashtable except may be as a debug
step to see the contents of the hashtable.

jliu - www.ssw.com.au - johnliu.net

With a For n=start to end step loop you would still have to worry if the
current element has been deleted by either this or another thread since the
start end & step are only evaluated once in the loop.
 
D

David

I'll chime in here with my longtime gripe.

The foreach implementation is flawed because the container is marked as
readonly during the iteration. This is a crime in my opinion because it is
*normal to effect a change on the container while iterating especially from
a vb point of view.

I see your point, but look at it from the implementers' point of view.

Making the container read-only allows for very efficient implementations
of the enumerator, and also makes writing new enumerators fairly simple.
Also, it eliminates a real ambiguity to the For Each statement, does
foreach iterate over the original collection, or over the entire
collection as it changes over time?

Dim i As Integer
For Each o as Object in MyCollection
i += 1
If i = 3 Then
MyCollection.Insert(0, new Object())
MyCollection.Add(New Object())
End If
Next

What would the iteration be in this case? Should both new objects be
iterated, or neither? Or just one? You could think of some reasonable
rules to apply to arrays, but what about things like hashes where
position doesn't have a fixed meaning? And how is the Enumerator
supposed to keep track of what's happening to the collection? Do we add
some kind of event to the IEnumerable interface? If so, that could turn
into a lot of overhead since the enumerator has to check for changes on
each iteration.

For efficiency's sake, maybe we could have two different enumeration
types, one for mutable containers and one for read-only, but then not
only are you complicating the class library tremendously, but calling
conventions can get strange (since only one of them can use For Each).

David
 
C

Cor Ligthert

Can you give some sample applications where this statement of you is true?
Although due to the nature of loops, they oftentimes fall into
the 20 percent of code that consumes 80 percent of the time.

It is in my opinion definitly not with applications where is by instance
screen painting or/and dataprocessing.

It is in my opinion definitly true for applications where is image
processing where not the GDI+ encoding is used.

However that is in my opinion surely not the majority of the applications.

So I am curious in what type of other applications stand alone loops can
consume 80% of the time?

Just my thought,

Cor
 
A

Alvin Bruney [MVP]

Making the container read-only allows for very efficient implementations
of the enumerator, and also makes writing new enumerators fairly simple.
Also, it eliminates a real ambiguity to the For Each statement, does
foreach iterate over the original collection, or over the entire
collection as it changes over time?

I don't disagree with that. very good point indeed. but, the current
approach makes it impossible to perform simple tasks inherent in UI
programming (like removing multiselects in a listbox for instance). Where
such simple tasks are overly complicated, i believe the design should be
reviewed.
For efficiency's sake, maybe we could have two different enumeration
types, one for mutable containers and one for read-only, but then not
only are you complicating the class library tremendously,

I think it is a reasonable approach. It would just be another way to iterate
a container and it shouldn't complicate matters since it could be made to
appear as an overload

but calling
conventions can get strange (since only one of them can use For Each).

That's really a design issue which needs to be hashed out in a way to make
this approach feasible.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top