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


in reply to shift vs @_

Arguments are passed into a subroutine via @_. Accessing one element or more of that array can be done in two ways, non-destructive (the @_ array persists as passed in) or destructive (the @_ array is consumed during assignment):
# 1. non-destructive my $var = $_[0]; # first element of @_ my @list = @_; # complete @_ # 2. destructive my $var = shift; # first element gets removed + from @_ my ($foo, $bar) = map { shift } 1,2; # two elements get removed f +rom @_

If @_ needs to be intact for subsequent calls, as in

sub foo { my $foo = $_[0]; my $quux = baz(@_) return $foo ^= $quux; }

the non-destructive methods are used. Also, as the variables passed in via the vector @_ are references aliases to the thingies the caller provided, the non-destructive way is often used to do in-place transformations.

Otherwise, it just doesn't matter. Since after setting up the variables in the sub's scope @_ isn't looked at anymore, arguments may be shifted or not. In these cases saying $var = shift or $var = $_[0] does the same for the sub, although the impact on @_ is different.

So, saying $var = shift and @list = @_ is just caring about copying, but done that, not caring about @_ any more.

Using the arguments in a sub without prior assignment (i.e. without copying, as $_[0] .. $_[$#_]) modifies the thingies in the caller.

--shmem

<update> changed reference to alias as per tye's post </update>

_($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                              /\_¯/(q    /
----------------------------  \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Replies are listed 'Best First'.
Re^2: shift vs @_
by BerntB (Deacon) on Oct 03, 2006 at 09:21 UTC
    Assume I have some large strings. I don't want them copied when I send them as parameters to subroutines/methods (which doesn't modify them).

    Do I have to use the $_[x] notation for that? Should I send them in as references?

      Both ways are ok. $_[0] is actually a reference (thanks, tye!) an alias to the first argument passed by the caller. You can evaluate (or operate on) $_[0] directly. Passing arguments as references just adds another level of indirection.

      You can also use prototypes for your subs and access your arguments inside the sub as references:

      #!/usr/bin/perl sub foo(\@\$) { warn "foo args: (".join(",",map{"'$_'"}@_).")\n"; print "1st argument = $_[0]; content =(" . join(',',map{"'$_'"} @{$_[0]}).")\n"; print "2nd argument = $_[1]; content = '".${$_[1]}."'\n"; my ($array,$scalar) = @_; push @$array, $$scalar; $$scalar = "blurf"; } my @ary = qw(foo bar baz); my $foo = "blah"; foo(@ary,$foo); print "ary: (@ary)\n"; print "foo: $foo\n";

      output:

      foo args: ('ARRAY(0x8167870)','SCALAR(0x8167978)') 1st argument = ARRAY(0x8167870); content =('foo','bar','baz') 2nd argument = SCALAR(0x8167978); content = 'blah' ary: (foo bar baz blah) foo: blurf

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        $_[0] is actually a reference to the first argument passed by the caller.

        I'm sure you know what you meant, but... $_[0] is (usually) an alias to the first argument. If it were a reference then you'd have to use ${$_[0]} or such.

        - tye