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

Warning: jptxs has recently completed Programming Perl and the knowledge is still settling : )

From a performance standpoint, is there any reason at all to pass anything but a reference into a subroutine? I mean, if you just end up clogging up more memory with the copied scaler/array (I take it for granted at this point hashes should be passed around as refs), can there be a situation where it would be better to pass an actual variable than a reference?

I'm sorry if this question is too broad - if so, just let me know. Just trying to get it all right as I can : )

-- I'm a solipsist, and so is everyone else. (think about it)

Replies are listed 'Best First'.
Re: passing refs to subs
by AgentM (Curate) on Oct 10, 2000 at 01:51 UTC
    This reference stuff carried over, of course, from C. Both are useful in certain situations, you simply must recognize them. Really, the speed issue should be an afterthought. When you pass by reference, you are passing almost the original object to the function. You can use this variable as if it had been called from the encapsulating function. When you return, the variable will remain what you set it in the calling function since any alteration in the function will have effect on the original variable. When you pass by reference, you are actually passing the variable's pointer address in memory.

    Now, when you pass by value, you are passing the actual variable's value when you called the function from the caller. This value is taken and a personal copy for that function and that function only is created. Any changes made to that copy do not affect any other variable in the system.

    Now, to your issue. In C, some variables are actually smaller than passing a pointer (reference), so the passing by value was actually preferable over passing by reference! But in Perl, there are no data types- even strings are held in the same variable. A typical string (keeping it simple) will easily eat up more than 16 or 32 bits (a typical pointer size). While internally, the pass is made with a pointer, perl will create a dynamic memory copy at some point before it continues in your code. If you do not need another copy to work on, pass by reference. In C, there is no penalty for pointers (references). In Perl, the penalty can become substantial- especially if you are derefencing in a loop- especially in a main or very important loop! In all cases, you should

    • consider whether you really need a function. Questions: Will i reuse this code again? Will I not be using it all too often (perhaps for a simple conversion only)? Do I need recursion?
    • consider which variables that you need to pass. Questions: Is this variable relevant in the function context?
    • choose pass ref or pass val. Questions: Will this variable remain constant throughout my function?(pass by val unnecessary) Do I need to take this variable and change it even in the encapsulating function? (reference required) Do I need my own copy of the variable for my own use without affecting other variables? (pass by val necessary unless you ref and then copy manually)
    Lastly, comes the speed check. As others have mentioned, Perl dereferencing takes time, so a Benchmark would be a good way to fly. On the other hand, sometimes it's obvious or irrelevant. Is the function only called once or twice in the program? Then the testing really won't reveal any mind-boggling speed increase. If the function is mission-critical and you really need that speed increase, go for it. Anyway, if you're using Perl, you're really not writing any OpenGL routines, so you should be all set with whatever you choose. If the shoe fits, wear it. One help may be to make sure that the user always has something to see. That means piping data straight to the user as it comes up (or in buffers thereof). That way, even if your program isn't fast, it'll seem fast!
    Q: Could a variable assignment bypass the perl dereference mechanism, as in:
    my $var=$bar->foo(); #deref here &var; #yet another deref?
    ? thanx.
    AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.

      It's not entirely clear what you're trying to do in your question, but you're a little confused about the syntax.

      To be able to call &var, there has to be an entry in the `var' stash's subroutine knob. In other words, you'd need to do this:

      local *var = sub { ... }

      So whatever you're doing above, if you're expecting $bar->foo() to return a subroutine reference, just stick it on the right side of my code there.

      And yes, by doing this, you eliminate the dereferecing step. However, see tilly's response to this node where I mention this technique for reasons why this isn't generally all that useful.

      -dlc

Re: passing refs to subs
by indigo (Scribe) on Oct 10, 2000 at 00:54 UTC
    You have to ask yourself what is slower...passing the array/hash, or the extra deference everytime you assess it. Typically, passing by reference is a win, but now always.

    Remember:
    $foo{'bob'};
    is faster than:
    $bar->{'bob'}; # Slower, extra dereference
    So if you have a small array/hash, and dereference it alot, code it both ways, and see what Benchmark tells you. I'm betting the difference will be small enough, you should be optimizing for readability instead.

    Also, remember using reference allows you to modify the actual variable, where normally you will just modify a copy. This, and not performance, will usually determine which you should use.
      Also, remember using reference allows you to modify the actual variable, where normally you will just modify a copy.

      I'm sure you understand what really happens in a sub, but your wording is a bit vague, so I'll clarify this for monks who might not be familiar with this issue.

      You will only modify a copy of a variable passed to a sub if you copy the arguments to new variables. If you modify the @_ array directly, you modify the original variables. Run the following snippet to see what I mean:

      #!/usr/bin/perl -w use strict; my $test = "Hi there!"; change($test); print $test; sub change { $_[0] = "Hey, this is different!\n"; }

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Re: passing refs to subs
by cianoz (Friar) on Oct 10, 2000 at 00:43 UTC
    all in all this is the old dilemma "pass by value" vs. "pass by reference" when you pass by reference you can alter the content of the original variable... (unless you make a copy inside the subroutine, but then where is the gain?)

      Actually, it's not quit that simple. Perl's standard calling convention isn't pass by value. The values that you get in @_ are aliases to the original variables, so changing @_ will change the values outside the subroutine, as this simple test demonstrates.

      my $x = 1; mult($x); print "$x\n"; sub mult { $_[0] *= 10; }
      --
      <http://www.dave.org.uk>

      "Perl makes the fun jobs fun
      and the boring jobs bearable" - me

RE: passing refs to subs
by extremely (Priest) on Oct 10, 2000 at 01:49 UTC
    When sending strings off to be mangled, do you want to keep the unmangled version? Send a copy, not a reference.

    Bet on about 90-95% pass by reference but don't get into the habit without thinking about it. It can BITE you when you least expect it.

    From the performance standpoint, really small lists don't matter =) On big lists, the answer is obvious.

    --
    $you = new YOU;
    honk() if $you->love(perl)