http://www.perlmonks.org?node_id=655489

Withigo has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
I have a question about how Perl internally works when returning from subroutines. I'm in a debate about whether it is a meaningful optimization to not use "return" and "return 1" in subroutines. What has been instead been proposed is to do something like this:
use constant Some::Module::TRUE => 1 == 1; use constant Some::Module::FALSE => 1 == 0; sub foo { return; } sub bar { return Some::Module::FALSE; }

Let's say foo() and bar() are called millions of times. The claim is the foo() is creating a new scalar (SV) upon each call and returning it, and that bar() is not making perl internally use more memory/cpu resources than it already has allocated. The claim is that perl does something magical with the result of '1 == 1' and '1 == 0', and does not create a new SV to represent the result of that operation.
However, I would think that something so fundamental as the simple return values from subs would already be optimized internally so as to not add needless overhead.
Can anyone confirm any of this?

Thanks!

Replies are listed 'Best First'.
Re: Not returning scalars(SV) to optimize and save memory?
by ikegami (Patriarch) on Dec 06, 2007 at 20:19 UTC
    Your influences are misleading you. The savings would be so minimal.... Let's put it to the test.
    use strict; use warnings; use Benchmark qw( cmpthese ); use constant TRUE => 1 == 1; use constant FALSE => 1 == 0; sub old_foo { return 0; } sub new_foo { return; } cmpthese(-3, { old_foo => 'old_foo(); 1', new_foo => 'new_foo(); 1', }); sub old_bar { return 1; } sub new_bar { return TRUE; } cmpthese(-3, { old_bar => 'old_bar(); 1', new_bar => 'new_bar(); 1', });

    The results fluctuated too much. Sometimes one is 20% faster than the other, sometimes it's the other way around. In other words, they are both so fast that the time they take is actually dependent on external factors.

    By the way, new_foo isn't even equivalent to old_foo.

Re: Not returning scalars(SV) to optimize and save memory?
by perrin (Chancellor) on Dec 06, 2007 at 23:48 UTC
    Regarding the memory used here, Perl will actually hold onto the memory used for creating a variable, even a lexical, in order to make it faster the next time through the sub. So, it won't cost you more memory to keep calling a sub that creates a return value, and it won't need to allocate the memory again after the first time through unless you put a much larger chunk of data into it.
Re: Not returning scalars(SV) to optimize and save memory?
by gamache (Friar) on Dec 06, 2007 at 20:16 UTC
    use Benchmark can tell us what is fastest:
    use strict; use constant FALSE => 1==0; use Benchmark qw(:all); cmpthese(1E7, { 'return;' => sub { return }, 'return FALSE;' => sub { return FALSE }, 'return 1==0;' => sub { return 1==0 }, 'implicit' => sub { }, 'implicit FALSE'=> sub { FALSE }, 'implicit 1==0' => sub { 1==0 }, });
    Results:
    Rate return FALSE; implicit FALSE return 1==0; i +mplicit return; implicit 1==0 return FALSE; 18281536/s -- -31% -54% + -63% -80% -92% implicit FALSE 26666667/s 46% -- -33% + -46% -71% -88% return 1==0; 40000000/s 119% 50% -- + -19% -56% -82% implicit 49261084/s 169% 85% 23% + -- -46% -77% return; 91743119/s 402% 244% 129% + 86% -- -58% implicit 1==0 217391304/s 1089% 715% 443% + 341% 137% --
    It seems that sub { 1==0 } crushes all comers, 137% faster than its closest competitor, return; aka sub foo from your example. (My guess is that Perl has optimized the subroutine away.) sub bar aka return FALSE comes in dead last, but keep in mind that use constant has rolled FALSE into a closure, so you get overhead for subroutine calls when you use it (which is indicated by both uses of FALSE being in last place).

    Not an examination of Perl's internal handling of SVs in subroutine returns, but a useful exploration of relative speed.

      And if you come up with a Perl subroutine that you can call 20 million times each second, then you might notice the speed difference. Of course, that will leave almost no time for your subroutine to do anything nor for the caller of the subroutine to do anything.

      Which is why such nano-optimization is a great way to waste your time.

      - tye        

        You caught me mid-brainfart. I wanted to type "relative" but somehow "real world" made it to my fingers first, though I was thinking of it in the context of this being an awful test of real-world conditions.
      I disagree with your conclusion. FALSE and 1==0 produce exactly the same code, yet in one place the results say one is 119% times the speed of the other, and in another place the results say one is 715% times the speed of the other.

      A better conclusion would be that the benchmark is useless. The reason might be that external factors (such as cache misses, context swapping) have a stronger influences on that the speed of those operations than the choice of operation.

Re: Not returning scalars(SV) to optimize and save memory?
by RaduH (Scribe) on Dec 06, 2007 at 20:19 UTC
    Well, here's my opinion based on whatI remember about programming languages design and implementation and not Perl in particular... The return in foo is useless so the only optimization I see here is to simply ignore it. It does not use memory and does nothing different from simply exiting the subroutine. In other cases, a similar return without parameters might actually make a difference because it might prevent other code in the subroutine to be executed and simply pops the stack and returns the control to the parent block of code that called the subroutine. It is a simple "traffic control" mechanism.

    For the second subroutine, you use memory when you return. I would argue that you create a result value (in this case a boolean, although Perl doesn't use booleans explicitly). Whatever that value is, it takes up memory space to store the result of your comparison. You may think that by defining the values above you save memory but you don't. You return a copy of that value. Even assuming return uses references (which I'd say is not the case) you'd still be using memory to store the reference to the value defined up top. Your bar return does more than flow of control, it actually passes a value up to the parent.

    For this reason, I think the claim that Perl does not use additional resources to represent that value internally is incorrect. It is a bool after all (Perl chooses not to call it so) but it is a value and that takes up space. If you optimize it to save that space it pretty much means you destroy what yo want to return. It seems you'd be looking for a meaningful value but are willing to spend zero to store it.

    Again, my 2c without knowing intimate details about how Perl handles the situation, but based on this line of thinking, I suspect there's little room for other scenarios. Anybody has any other idea?