Which one of these do you prefer?
foreach(var zombie in zombies)
{
zombie.ShuffleTowardsSurvivors();
zombie.EatNearbyBrains();
}
or
zombies.Each(zombie => {
zombie.ShuffleTowardsSurvivors();
zombie.EatNearbyBrains();
});
Which one of these do you prefer?
foreach(var zombie in zombies)
{
zombie.ShuffleTowardsSurvivors();
zombie.EatNearbyBrains();
}
or
zombies.Each(zombie => {
zombie.ShuffleTowardsSurvivors();
zombie.EatNearbyBrains();
});
The first. It's part of the language for a reason.
Personally, I'd only use the second, functional approach to flow control if there is a good reason to do so, such as using Parallel.ForEach
in .NET 4. It has many disadvantages, including:
foreach (..) { myDelegate(); }
I see no reason to write your own syntax for a flow control construct that already exists in the language.
I don't prefer either, because of what I consider to be an un-needed use of 'var'. I would write is as:
foreach(Zombie zombie in zombies){
}
But as to the Functional or foreach, for me I most definitely prefer foreach, because there doesn't seem to be a good reason for the latter.
This question contains some useful discussion, as well as a link to an MSDN blog post, on the philosophical aspects of the topic.
I'd think the second form would be tougher to optimize, as there's no way for the compiler to unroll the loop any differently for this one call than it does for anybody else's call to the Each method.
Since it was asked, I'll elaborate. The method's implementation is quite liable to be compiled separately from the code that invokes it. This means that the compiler does not know exactly how many loops it is going to have to perform.
If you use the "foreach" form then that information may be avaliable to the compiler when it is creating the code for the loop (it also may not be available, in which case no difference).
For example, if the compiler happens to know (from previous code in the same file) that the list has exactly 20 items in it, it can replace the entire loop with 20 references.
However, when the compiler creates code for the "Each" method off in its source file, it has no idea how big the caller's list is going to be. It has to support any size. The best it can do is try to find some kind of optimum unrolling for its CPU, and add extra code to loop through that and do a proper loop if it is too small for the unrolling. For a typical small loop this might even end up being slower. Of course for small loops you don't care as much....unless they happen to be inside a big loop.
As another poster mentioned, this is (and should be) a secondary concern. The important thing is which is easier to read and/or maintain, but I don't see a huge difference there.
Second form.
In my opinion, the less language constructs and keywords you have to use, the better. C# has enough extraneous crud in it as it is.
Generally the less you have to type, the better. Seriously, how could you not want to use "var" in situations like this? Surely if being explicit was your only goal, you'd still be using hungarian notation... you have an IDE that gives you type information whenever you hover over... or of course Ctrl+Q if you're using Resharper...
@T.E.D. The performance implications of a delegate invocation are a secondary concern. If you're doing this a thousand terms sure, run dot trace and see if it's not acceptable.
@Reed Copsey: re non-standard, if a developer can't work out what ".Each" is doing then you've got more problems, heh. Hacking the language to make it nicer is one of the great joys of programming.
The lamda version is actually not slower. I just did a quick test and the delegate version is about 30% faster.
Here is the codez:
class Blah {
public void DoStuff() {
}
}
List<Blah> blahs = new List<Blah>();
DateTime start = DateTime.Now;
for(int i = 0; i < 30000000; i++) {
blahs.Add(new Blah());
}
TimeSpan elapsed = (DateTime.Now - start);
Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "Allocation - {0:00}:{1:00}:{2:00}.{3:000}",
elapsed.Hours,
elapsed.Minutes,
elapsed.Seconds,
elapsed.Milliseconds));
start = DateTime.Now;
foreach(var bl in blahs) {
bl.DoStuff();
}
elapsed = (DateTime.Now - start);
Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "foreach - {0:00}:{1:00}:{2:00}.{3:000}",
elapsed.Hours,
elapsed.Minutes,
elapsed.Seconds,
elapsed.Milliseconds));
start = DateTime.Now;
blahs.ForEach(bl=>bl.DoStuff());
elapsed = (DateTime.Now - start);
Console.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "lambda - {0:00}:{1:00}:{2:00}.{3:000}",
elapsed.Hours,
elapsed.Minutes,
elapsed.Seconds,
elapsed.Milliseconds));
OK, So I've run more tests and here are the results.
The order of the execution(forach, lambda or lambda, foreach) didn't make much difference, lambda version was still faster:
foreach - 00:00:00.561 lambda - 00:00:00.389 lambda - 00:00:00.317 foreach - 00:00:00.337
The difference in performance is a lot less for arrays of classes. Here are the numbers for Blah[30000000]:
lambda - 00:00:00.317 foreach - 00:00:00.337
Here is the same test but Blah being a struct:
Blah[] version lambda - 00:00:00.676 foreach - 00:00:00.437 List version: lambda - 00:00:00.461 foreach - 00:00:00.391
Optimized build, Blah is a struct using an array.
lambda - 00:00:00.426 foreach - 00:00:00.079
Conclusion: There is no blanket answer for performance of foreach vs lambda. The answer is It depends. Here is a more scientific test for List<T>
. As far as I can tell it's pretty damn efficient. If you are really concerned with performance use for(int i...
loop. For iterating over a collection of a thousand customer records (example) it really doesn't matter all that much.
As far as deciding between which version to use I would put potential performance hit for lambda version way at the bottom.
Conclusion #2 T[]
(where T is a value type) foreach loop is about 5 times faster for this test in an optimized build. That's the only significant difference between a Debug and Release build. So there you go, for arrays of value types use foreach, everything else - it doesn't matter.
Here you're doing some very imperative things like writing a statement rather than an expression (as presumably the Each
method returns no value) and mutating state (which one can only assume the methods do, as they also appear to return no value) yet you're trying to pass them off as 'functional programming' by passing a collection of statements as a delegate. This code could barely be further from the ideals and idioms of functional programming, so why try to disguise it as such?
As much as I like multi-paradigm languages such as C#, I think they are easiest to understand and maintain when paradigms are mixed at a higher level (e.g. an entire method written in either a functional or an imperative style) rather than when multiple paradigms are mixed within a single statement or expression.
If you're writing imperative code just be honest about it and use a loop. It's nothing to be ashamed of. Imperative code is not an inherently bad thing.
I think extension methods are cool, but I think break
and edit-and-continue are cooler.