Side note: map in void context no longer carries the overhead that it did and, in any event, if you must apply the same behavior to every element in a list, many programmers find using map is often clearer than foreach. Sometimes it's just a stylistic thing.
Of course, you point out that the word "map" can be misleading, but if one merely thinks of the word "apply" or something else in place of map, it makes more sense. After all, Lisp programmers have gotten along with lambda for many years. (Not to mention car and cdr!)
| [reply] |
For me it's more a matter of clarity/readability for someone looking over my code, particularly with nested maps like this (do you really find map { map { ... } @bar } @foo easier to mentally parse than foreach (@foo) { foreach (@bar) { ... } }?). But, you're right...it's mostly a stylistic thing and this is a classic example of TMTOWTDI.
Update: I tried a little test and foreach was actually significantly faster (for this particular test, that is):
#!perl -w
use strict;
use Benchmark;
Benchmark::cmpthese(-5, {
'foreach' => sub { my $sum=0; foreach (1..100) { foreach (1..100)
+{ $sum++ }}},
'map' => sub {my $sum=0; map { map { $sum++ } (1..100) } (1..100)
+},
});
------------------------------
Rate map foreach
map 345/s -- -43%
foreach 603/s 75% --
What gives?
| [reply] [d/l] [select] |
What version of Perl are you using and on which platform? perl -V would be nice. I'm not saying map is faster, but then, I'm not really worried about it. I'm more worried about code correctness and maintainability.
One interesting thing about map and friends which is not appreciated enough is how map says "do this for everything in the list" when foreach says "do this to each thing in the list." It's a subtle distinction, but one study of programming discovered that programmers tend to make fewer errors when using commands that operate on an entire set instead of looping constructs that operate on individual members of the set. Unfortunately for most programmers, we're given tools for the latter while the former are often considered "advanced" when in reality their simpler. We get taught the bad way and we get used to it. Go figure :)
| [reply] |
Two things are important here. First is that foreach (N..M) is an optimized construct - map {} N..M isn't. Second is that a foreach() is slightly faster than a map. So, if you do 101 of them, it adds up. Here's a somewhat different test:
use strict;
use warnings;
use Benchmark 'cmpthese';
my $nums1 = join(",", 1..100);
my $nums2 = "1..100";
cmpthese(-1, {
for1 => "my \$sum=0; foreach ($nums1) {\$sum++}",
for2 => "my \$sum=0; foreach ($nums2) {\$sum++}",
for3 => "my \$sum=0; \$sum++ foreach ($nums1)",
for4 => "my \$sum=0; \$sum++ foreach ($nums2)",
map1 => "my \$sum=0; map {\$sum++} $nums1",
map2 => "my \$sum=0; map {\$sum++} $nums2",
map3 => "my \$sum=0; map \$sum++, $nums1",
map4 => "my \$sum=0; map \$sum++, $nums2",
});
__END__
Rate map1 map3 map2 map4 for1 for3 for2 for4
map1 33185/s -- -3% -5% -5% -9% -17% -25% -34%
map3 34296/s 3% -- -1% -2% -6% -15% -22% -32%
map2 34795/s 5% 1% -- -0% -5% -13% -21% -31%
map4 34909/s 5% 2% 0% -- -5% -13% -21% -31%
for1 36571/s 10% 7% 5% 5% -- -9% -17% -27%
for3 40193/s 21% 17% 16% 15% 10% -- -9% -20%
for2 43997/s 33% 28% 26% 26% 20% 9% -- -12%
for4 50243/s 51% 46% 44% 44% 37% 25% 14% --
Note that the differences between 'map1' and 'map3' and between 'map2' and 'map4' are smaller than the differences between 'for1' and 'for3' and the difference between 'for2' and 'for3'. And that the non-optimized fors ('for1' and 'for3') are somewhat faster than the equivalent maps ('map1' and 'map3'). Now, if you do that 101 times, I'm surprised the difference is only 75%.
Perhaps the most interesting number in the above table is the 51% in the lower left corner. It means that if you compare the fastest foreach (expression form, optimized range), and pit that against the slowest map (block form, no range), and have a very minimal body, thus giving the loop overhead a significant weight, your gain is still only about 50%. | [reply] [d/l] [select] |