While talking to revdiablo about the details behind the behavior of $_ vs. argument passing, I threw together this example of where things in Perl aren't always well-understood.

In C, the following code:

// hypothetical struct x if (flag) { x->y->z->a->b[5]->q = 8; x->y->z->a->b[5]->r = 9; }
gets compiled very efficiently with optimizations turned on, due to a standard optimization called 'common subexpression elimination' (heretofore referred to as 'CSE'). In effect, the compiler does this:
if (flag) { t = x->y->z->a->b[5]; t->q = 8; t->r = 9; }
Thus, the compiler only has to perform all these dereferences *once*. Unfortunately, unlike C, Perl has to contend with something a little crazier: Tied hashes and arrays. The nature of tied hashes and arrays makes certain things impossible, including CSE. To illustrate my point, I created a benchmark:
#!/usr/bin/perl use strict; use warnings; use Time::HiRes; use Benchmark qw(cmpthese :hireswallclock); my @bogus; $bogus[1]{foo}[2]{bar}[3]{baz} = 5; $bogus[1]{foo}[2]{bar}[3]{quux} = 6; our @bogus2; $bogus2[1]{foo}[2]{bar}[3]{baz} = 5; $bogus2[1]{foo}[2]{bar}[3]{quux} = 6; cmpthese(1_000_000, { without_common => sub { my $prod = $bogus[1]{foo}[2]{bar}[3]{baz} * $bogus[1]{foo}[2]{bar}[3]{quux}; }, with_common => sub { my $common = $bogus[1]{foo}[2]{bar}[3]; my $prod = $common->{baz} * $common->{quux}; }, without_common_g => sub { my $prod = $bogus2[1]{foo}[2]{bar}[3]{baz} * $bogus2[1]{foo}[2]{bar}[3]{quux}; }, with_common_g => sub { my $common = $bogus2[1]{foo}[2]{bar}[3]; my $prod = $common->{baz} * $common->{quux}; }, });
The results on my machine are as such:
Rate without_common_g without_common with_common_ +g with_common without_common_g 341880/s -- -4% -20 +% -23% without_common 357910/s 5% -- -16 +% -19% with_common_g 428449/s 25% 20% - +- -3% with_common 443853/s 30% 24% 4 +% --
Note carefully that with_common runs 24% faster than without_common. That's because, even with the extra variable, the three array index and two hash key lookups saved in with_common more than compensate for the extra variable assignment.

Also note the 4-5% difference between with_common/without_common and their _g equivalents. This is *entirely* due to the extra hash lookup required to get the address of the global 'bogus2'. This hash lookup is ALWAYS required due to dynamic scoping requirements.

Morals of the story:


Update: Realized how long this node is, added readmore.
--Stevie-O
$"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc

In reply to Perl and common subexpressions by Stevie-O

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.