Recursion is very elegant in my opinion, but its performance is relatively horrible. Using globals to eliminate recursion gives you a huge gain in performance, but globals are to be equally avoided to foster maintainable code. The other options are to use "regular" lexical variables or those within closures.

We avoid the use of globals because:

But their performance outweighs that cost sometimes. Might there be some middle ground?

I decided to explore the other options a bit, and it appears that globals and lexicals are almost identical in performance and closure performance is only slightly slower.

Here is the test code and its results:

#!/usr/bin/perl -w use strict; use Benchmark qw/:all/; my $iGlobal; my $x = 4; timethese (1000000, { 'Recursion' => 'Rfactorial(30)', 'Global' => 'Gfactorial(30)', 'Lexical' => 'Lfactorial(30)', 'Closure' => '&{Cfactorial()}(30)', } ); # A classic, recursive soulution. sub Rfactorial { my $i = shift; return 1 if $i == 0; return 1 if $i == 1; return $i * Rfactorial($i - 1); } # Rewritten to use global variables. sub Gfactorial { $iGlobal = shift; return 1 unless $iGlobal > 1; my $result = 1; while ($iGlobal > 1) { $result = $result * $iGlobal; $iGlobal--; } return $result; } # expressed with lexicals sub Lfactorial { my $iLexical = shift; return 1 unless $iLexical > 1; my $result = 1; while ($iLexical > 1) { $result = $result * $iLexical; $iLexical--; } return $result; } # Rewritten to use closures sub Cfactorial { my $iClosure; return sub { my $iClosure = shift; my $result = 1; while ($iClosure > 1) { $result = $result * $iClosure; $iClosure --; } return $result; } }
and the results
Benchmark: timing 1000000 iterations of Closure, Global, Lexical, Recu +rsion... Closure: 66 wallclock secs (61.70 usr + 0.00 sys = 61.70 CPU) @ 16 +207.46/s (n=1000000) Global: 62 wallclock secs (58.39 usr + 0.00 sys = 58.39 CPU) @ 17 +126.22/s (n=1000000) Lexical: 63 wallclock secs (58.55 usr + 0.00 sys = 58.55 CPU) @ 17 +079.42/s (n=1000000) Recursion: 208 wallclock secs (176.95 usr + 0.00 sys = 176.95 CPU) @ + 5651.31/s (n=1000000)
I take from the tests is that recoding a recursive routine to use lexicals is, overall, a better option than globals. Closures would give great gains too, but I can't think of an example in which they provide functionality beyond a simple, lexical arrangement.

Do the other monks have more insight?

update (broquaint): changed <pre> tags to <code> tags around the Benchmark result

Edit by tye, add READMORE


In reply to Recursion Alternatives? by Cabrion

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.