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

Dear Master Monks,

In Learning Perl I see my $blah = @_; and in the Camel, I see my $blah = shift;

Why the difference? Do they not do the same thing?

Update: I meant my ($blah) = @_;

Thanks,

Gavin.

Walking the road to enlightenment... I found a penguin and a camel on the way.....
Fancy a yourname@perl.me.uk? Just ask!!!

Replies are listed 'Best First'.
Re: Subroutines: @_ and shift
by gaal (Parson) on May 14, 2005 at 09:18 UTC
    my $blah = @_ is almost always not what you want. Pick one of these:

    my ($blah) = @_; # note the ()s. w/o them $blah is the size of @_. my $blah = shift;

    shift modifies @_, which *typically* you don't need to do. For that reason, and for consistency with cases where my method takes args, I prefer the @_ syntax.

    my ($first, $second, @rest) = @_;

    In OOP, occasionally you want to delegate part of your work to another method. In that case shift sometimes makes sense. You might see code like this.

    sub frontend { shift->backend("an extra arg", @_) }

    Update: Perl6 - how could I forget :)

    In Perl6, you don't normally need to access @_ explicitly. Declare the formal argument and that's that.

    sub mine ($blah) { say "$blah is now visible here."; }
Re: Subroutines: @_ and shift
by mlh2003 (Scribe) on May 14, 2005 at 13:32 UTC
    The other difference is that:
    my (@blah) = @_;
    basically copies all parameters passed to the array from @_ to @blah. It leaves @_ intact (for other processing if required).

    Whereas:
    my $blah = shift;
    will REMOVE the first element of the parameter array @_ and place it in the $blah scalar. 'shift'ing will shorten the @_ array. This, as gaal mentioned, modifies @_.
    _______
    Code is untested unless explicitly stated
    mlh2003
Re: Subroutines: @_ and shift
by tlm (Prior) on May 14, 2005 at 11:04 UTC

    Are you sure you are quoting Learning Perl fairly? I suspect that what you saw was

    my ($blah) = @_;
    which, like
    my $blah = shift;
    assigns the first element of @_ to $blah, although the form using shift has the additional effect of removing this first element from @_. Or maybe you saw
    my @blah = @_;
    which assigns all of @_ to the array @blah.

    In contrast, what you quoted,

    my $blah = @_;
    just assigns to $blah the size of @_.

    the lowliest monk

Re: Subroutines: @_ and shift
by polettix (Vicar) on May 14, 2005 at 12:23 UTC
    As said by gaal, in OOP code it's a common idiom; Learning Perl Objects, References and Modules suggests using shift.

    I also find the shift idiom useful when I have a function that acts on a list of arguments based on the very first parameters; in this way, instead of:

    sub somesub { my ($first, $second, @list) = @_ foreach my $element (@list) { # do something, possibly intelligent } }
    you can avoid a list copy using:
    sub somesub_nocopy { my $first = shift; my $second = shift; foreach my $element (@_) { # do something, possibly intelligent } }
    BUT this way you can produce side-effects outside the functions, due to @_ aliasing, so you've to be careful; from perldoc perlsub:
    Any arguments passed in show up in the array @_. Therefore, if you called a function with two arguments, those would be stored in $_[0] and $_[1]. The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable). If an argument is an array or hash element which did not exist when the function was called, that element is created only when (and if) it is modified or a reference to it is taken. (Some earlier versions of Perl created the element whether or not the element was assigned to.) Assigning to the whole array @_ removes that aliasing, and does not update any arguments.

    Update: rephrased to avoid implying that gaal is suggesting to actually use shift other than for facade methods.

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.

      I just started reading Learning Perl Objects, References and Modules this morning, so I should get to the shift soon.

      Thanks.

      Walking the road to enlightenment... I found a penguin and a camel on the way.....
      Fancy a yourname@perl.me.uk? Just ask!!!
Re: Subroutines: @_ and shift
by thcsoft (Monk) on May 14, 2005 at 10:26 UTC
    the @_ array contains all the scalars a subroutine has got as its arguments. 'shift' without any parameter acts on this array. for a first overview take a look at 'perldoc perlvar', 'perldoc perlsub', and lateron at 'perldoc perlref'.

    language is a virus from outer space.
Re: Subroutines: @_ and shift
by johnnywang (Priest) on May 15, 2005 at 00:58 UTC
    Another related point is that it's important to use the two constructs under discussion, rather than working on @_ directly (unless that's what you want). @_ is passed in by referecne, most of the time, we work on local copies within the sub.
    use strict; my $a = 1; change($a); print "a is now: $a\n"; not_change($a); print "a is now: $a\n"; sub change{ ++$_[0]; } sub not_change{ my $b = shift; ++$b; } __OUTPUT__ a is now: 2 a is now: 2
Re: Subroutines: @_ and shift
by sh1tn (Priest) on May 14, 2005 at 09:36 UTC
    my @a = 1..10; { my $s = shift @a; print "$s\n" #result: 1 which is the 1st @a array element } { my $s = @a; print "$s\n" #result: 9 which is the number of @a array elements }
    The same is valid for shift and @_.
    You may want to take a look at perldoc -f shift.