Reputation: 25223
shift
Shifts the first value of the array off and returns it...
This is done for speed optimization and to avoid copying by value.
Also in perlsub
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
Thus if we do my $self = shift
in our sub, we shift the first value from @_
, which is an alias, is it not?
But when we compare these two:
sub test {
print \$_[0]; # SCALAR(0xf73c38)
my $x = shift;
print \$x; # SCALAR(0xf79800)
}
We see that $x
is the copy.
Why is the shift
ed value from @_ not an alias?
So if the value is copied for the case my $x = shift
too, what benefit does it provide over my $x = $_[0]
?
Upvotes: 3
Views: 177
Reputation: 386461
shift
isn't an lvalue operator.
$ perl -e'
use feature qw( say );
sub f { shift = 456; }
{ my $x = 123; f($x); say $x; }
'
Can't modify shift in scalar assignment at -e line 3, near "456;"
Execution of -e aborted due to compilation errors.
However, the values shifted from @_
are aliases nonetheless.
$ perl -e'
use feature qw( say );
sub f { my $p = \shift; $$p = 456; }
{ my $x = 123; f($x); say $x; }
'
456
or
$ perl -e'
use feature qw( say );
sub f { ${ \shift } = 456; }
{ my $x = 123; f($x); say $x; }
'
456
The problem is that you assigned the value of the aliased array element to $x
rather than aliasing $x
to array element. If you want to name the element of @_
, you will need to alias a variable to it.
$ perl -e'
use feature qw( say );
sub f { our $x; local *x = \shift; $x = 456; }
{ my $x = 123; f($x); say $x; }
'
456
or
$ perl -e'
use feature qw( say );
use Data::Alias qw( alias );
sub f { alias my $x = shift; $x = 456; }
{ my $x = 123; f($x); say $x; }
'
456
or
$ perl -e'
use feature qw( say refaliasing );
no warnings qw( experimental::refaliasing );
sub f { \my $x = \shift; $x = 456; }
{ my $x = 123; f($x); say $x; }
'
456
The benefits of my $x = shift
over my $x = $_[0];
are numerous, although minor.
shift
is easier to type than $_[0]
.shift
for each rather than keeping count.shift
supports complex and open-ended parameters lists. (e.g. sub f { my $cb = shift; $cb->($_) for @_; }
)shift
is microscopically faster than $_[0]
(IIRC).Upvotes: 3
Reputation: 118665
The shifted value is an alias
$ perl -E 'sub F{say \$_[0]; say \shift} $x=42; say \$x; F($x)'
SCALAR(0x1d7f1e0)
SCALAR(0x1d7f1e0)
SCALAR(0x1d7f1e0)
The assignment operation (e.g., $x = $_[0]
or $x = shift
) creates a copy of the scalar on the right hand side, so the newly assigned value is no longer an alias.
As toolic said, the benefit of shift
is to modify @_
, which sometimes makes it easier to use in the rest of your subroutine.
You could still work with a reference to the shifted value if you still wanted to be able to modify the input
$ perl -E 'sub G { my $x=\shift; $$x = 19 } my $z = 42; G($z); say $z'
19
Upvotes: 9