One of the things that we all love about Perl is TMTOWTDI. The options allow us to excerise our creativity in many ways, however it has its down side. Having so many options to choose from means we need to be all the more discriminatory as to the choices we make. An example is that recently I've been browsing through the Monastery archives and I've noticed is what to me are lots of inappropriate looping constructs being used. Read ineffecient for inappropriate. They seem to be used incorrectly either because the author comes from a C background and is unaware that looks are deceiving, or because the author misunderstands basic perl ideas.

Now before I go further lets deal with the 'If you want fast then you shouldn't be using Perl, use C' objections. Crap. That kind of logic would lead someone who has just discovered that their Perl bubblesort implementation is too slow to rwrite it in C, instead of doing the obvious and using perls built in sort. Why would I want to use code that is twice as slow as code that is just is easy to write in the same language?? Sure if overall kickass speed was the bottom line I wouldnt use Perl. But being aware of and taking advantage of the optimizations that Perl allows isn't wrong, its smart.

The inappropriate loop structure I see the most is the 3 argument for. Any time I see this being used to iterate over numbers from $lower to $higher I assume the author is inexperienced in the Perl world, when its an experienced member of the community I basically wonder what they were thinking.

The next is the inappropriate use of grep and map. grep seems to be the ideal subject for abuse. Lots of people seem to think of it as an 'element finder'. Uh, No. Its a filter. The idea is for it to be used on lots of elements to find subsets of the original elements, normally more than one. There are _much_ more efficient ways of finding a single element in an array. map() is abused in a similar way. It is NOT a for loop. Ok, if you're writing an obfu, or you _really_ dont care about speed then fine use map or grep. But its a piece of shorthand that should be used only rarely, that is when you need to transform most elements from one array into a different set of elements in a new array. Incidentally if you decide to use map or grep in void context then grep seems to be faster.

So heres what to keep in mind:

So to put a little money where my mouth is here are some benchmarks.
use Benchmark 'cmpthese'; our $n=10; our $sum=0; cmpthese (-5,{ 'grep{}' => '$sum=0; grep {$sum+=$_} 0..$n;', 'grep()' => '$sum=0; grep ($sum+=$_,0..$n);', 'map{}' => '$sum=0; map {$sum+=$_} 0..$n;', 'map()' => '$sum=0; map ($sum+=$_,0..$n);', 'for_modif' => '$sum=0; $sum+=$_ foreach 0..$n;', 'foreach' => '$sum=0; foreach my $i (0..$n) {$sum+=$i} +', 'for(;;)3' => '$sum=0; for (my $i=0;$i<=$n;$i++) {$sum+ +=$i}', 'for(;;)2' => '$sum=0; for (my $i=0;$i++<=$n;) {$sum+=$ +i}', 'w{}c{}' => '$sum=0; my $i=0; while($i<=$n){$sum+=$i} +continue{$i++}', 'while' => '$sum=0; my $i=0; while($i<=$n){$sum+=$i+ ++};', }); __END__ #last two columns removed for space reasons Rate map{} grep{} map() for(;;)3 w{}c{} grep() for(;;)2 w +hile map{} 39416/s -- -3% -21% -34% -34% -41% -45% +-47% grep{} 40750/s 3% -- -18% -32% -32% -39% -44% +-46% map() 49897/s 27% 22% -- -16% -17% -25% -31% +-33% for(;;)3 59526/s 51% 46% 19% -- -0% -11% -18% +-21% w{}c{} 59804/s 52% 47% 20% 0% -- -10% -17% +-20% grep() 66614/s 69% 63% 34% 12% 11% -- -8% +-11% for(;;)2 72308/s 83% 77% 45% 21% 21% 9% -- + -4% while 75007/s 90% 84% 50% 26% 25% 13% 4% + -- foreach 80124/s 103% 97% 61% 35% 34% 20% 11% + 7% for_modif 84073/s 113% 106% 68% 41% 41% 26% 16% + 12%
Now this all applies to 5.6, I'd be interested in knowing how it differs from earlier version.

Anyway, I suppose this is a bit of a rant, but its something that has gotten to me a bit lately, especially respected members of our community posting what I consider to be 'clever but BS' solutions to problems. To me if a solution is not as effecient as is reasonable then it shouldnt be posted.

:-)

Yves
--
You are not ready to use symrefs unless you already know why they are bad. -- tadmc (CLPM)


In reply to Efficient Looping Constructs by demerphq

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.