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

I am in the middle of a large project and find myself in a position where it is necessary to use pass-by-reference. My problem is more one of style and good coding practices than it is a "How do I do this" question.

My first thought is do something like this:

package snafu; sub foo { my $bar = shift; # Interesting things happen $$bar = $baz; if ( $things_worked ) { return SUCCESS_CODE; else { return FAILURE_CODE; } }
I do not like the call syntax I am left with:
unless ( $fsck->foo(\$variable) == SUCCESS_CODE ) { die "That was quite grim"; }
because I find the extra slash somewhat jarring - it breaks the flow of the code.

The other way I know of doing pass-by-reference in perl is like this:

package snafu; sub foo { # interesting things happen $_[0] = $baz; if ( $things_worked ) { return SUCCESS_CODE; else { return FAILURE_CODE; } }
It gives me a nicer calling syntax
unless ( $fsck->foo($variable) ) { die "A terrible way to go"; }
but I cannot help feeling that the @_ trick is somehow evil and not a very nice thing to do to a variable.

Is there a preferred way of doing this? In the experience of the other Monks, which makes more sense? Is the @_ trick really an evil thing or am I being squeamish? Have I missed something obvious?

TIA,
mikfire

Replies are listed 'Best First'.
Re: Pass by reference: is it good form to grope @_?
by chipmunk (Parson) on Dec 15, 2000 at 23:55 UTC
    The aliasing of the elements of @_ to the actual call values is an intentional feature. It's exactly what you're looking for, so I say go ahead and use it. You may also want to use a prototype of (\$), to ensure that the calling code doesn't pass in a constant.

    Of course, the documentation for the subroutine should specify that it modifies its argument in place.

      The only problem with prototyping like this is that object methods cannot be protoyped, so it would have no effect. A constant would be passed, ignoring the prototype.
Re: Pass by reference: is it good form to grope @_?
by mirod (Canon) on Dec 16, 2000 at 00:00 UTC

    When I need a subroutine to modify one (or more) scalar variables I usually use a 3rd method: I send the value back in the return.

    It seems that you want the subroutine to return a status. But even then couldn't you use undef as a failure signal?

    unless( defined( $variable= foo( $variable))) die "horrible death: $sn +afu::ERROR"; package snafu; my $ERROR; sub foo { # interesting things happen if ( $things_worked ) { return $baz; else { $ERROR= "horrible death"; return undef; }

    I actually very rarely modify $_[0] and al. I don't like side effects and I prefer to see clearly which variables are modified by a function.

Re: groping @_ (judiciously)
by Russ (Deacon) on Dec 16, 2000 at 00:27 UTC
    I have to weigh in against the "silently modify the arguments" approach. Of course good (and very LOUD) documentation can offset most of the danger, but most people don't expect to have arguments modified by a subroutine.

    IM(ns)HO, the occasional '\' is a very small price to pay for self-documenting code. If it strikes you as jarring, I think that is all the more reason to use it. You (and the one who maintains your code) will instantly recognize an atypical behavior when you see an unusual syntax in use.

    I don't think the @_ trick is evil. There is a time and place to use it, just like the &func construct (re-using the current @_), but it should only be used judiciously.

    Russ
    Brainbench 'Most Valuable Professional' for Perl

Re: Pass by reference: is it good form to grope @_?
by merlyn (Sage) on Dec 15, 2000 at 23:59 UTC
    I prefer that the subroutine not muck with my arguments, unless I pass an explicit reference. The fiasco around HTML::Entities's encode_entities showed that this is bourne out in general. And in fact, we had a thread about that here a while back.

    -- Randal L. Schwartz, Perl hacker

Re: Pass by reference: is it good form to grope @_?
by Dominus (Parson) on Dec 18, 2000 at 21:35 UTC
    Says mikfire:
    > Is the @_ trick really an evil thing or am I being squeamish?
    On this question my vote is "guilty until proven innocent".

    Sometimes the @_ trick is a good way to go. One common example is:

    sub trim { for (@_) { s/^\s+//; s/\s+$//; } }
    And then you call trim($a, $b) to trim leading and trailing whitespace from $a and $b.

    Cases like this come under the heading of 'doing something weird'. When you do something weird, you need to make sure people know about it. One thing that's important is to give the function a suggestive name. In your question you left out a crucial piece of information: The name of the method. All you told us was that it was called foo. But the name is very important here.

    If you call the method is_yellow, then it's a very bad idea to have it modify its argument. But if it's called set_argument_to_57 then it might not be so bad.

Re: Pass by reference: is it good form to grope @_?
by mikfire (Deacon) on Dec 18, 2000 at 20:11 UTC
    I would like to thank my fellow Monks for their input. In reading the several replies, I decided what bothered me most about messing with @_ is it violates POLA ( Principle Of Least Astonishment ). Which sometimes must be done, but in this case I will live with a slightly messier calling syntax.

    Thanks to chipmunk for the prototyping suggestion - I would have never thought to do that. Unfortunately, I am in using a method call syntax and, according to the manpages, prototypes are ignored.

    Special thanks to both Russ and merlyn for allowing me to specifically determine why groping @_ makes me nervous.

    Mik
    mikfire