I'm frequently using shift
to unpack function parameters:
sub my_sub { my $self = shift; my $params = shift; .... }
However, many on my colleagues are preaching that shift
is actually evil. Could you explain why I should prefer
sub my_sub { my ($self, $params) = @_; .... }
to shift
?
Perl | shift() Function shift() function in Perl returns the first value in an array, removing it and shifting the elements of the array list to the left by one. Shift operation removes the value like pop but is taken from the start of the array instead of the end as in pop.
Passing Arguments to a Subroutine You can pass various arguments to a subroutine like you do in any other programming language and they can be acessed inside the function using the special array @_. Thus the first argument to the function is in $_[0], the second is in $_[1], and so on.
Yes, there is a difference between the two. shift would change the @_ (You could argue this would be an operation that would make shift slower) $_[0] or $_[1] is just assignment and would not change @_ at all. shift is not that much slower than simple assignment. It really depends on what you want to do.
In general, passing parameters by references means that the subroutine can change the values of the arguments. The changes also take effect after the subroutine ends.
The use of shift
to unpack arguments is not evil. It's a common convention and may be the fastest way to process arguments (depending on how many there are and how they're passed). Here's one example of a somewhat common scenario where that's the case: a simple accessor.
use Benchmark qw(cmpthese); sub Foo::x_shift { shift->{'a'} } sub Foo::x_ref { $_[0]->{'a'} } sub Foo::x_copy { my $s = $_[0]; $s->{'a'} } our $o = bless {a => 123}, 'Foo'; cmpthese(-2, { x_shift => sub { $o->x_shift }, x_ref => sub { $o->x_ref }, x_copy => sub { $o->x_copy }, });
The results on perl 5.8.8 on my machine:
Rate x_copy x_ref x_shift x_copy 772761/s -- -12% -19% x_ref 877709/s 14% -- -8% x_shift 949792/s 23% 8% --
Not dramatic, but there it is. Always test your scenario on your version of perl on your target hardware to find out for sure.
shift
is also useful in cases where you want to shift off the invocant and then call a SUPER::
method, passing the remaining @_
as-is.
sub my_method { my $self = shift; ... return $self->SUPER::my_method(@_); }
If I had a very long series of my $foo = shift;
operations at the top of a function, however, I might consider using a mass copy from @_
instead. But in general, if you have a function or method that takes more than a handful of arguments, using named parameters (i.e., catching all of @_
in a %args
hash or expecting a single hash reference argument) is a much better approach.
It is not evil, it is a taste sort of thing. You will often see the styles used together:
sub new { my $class = shift; my %self = @_; return bless \%self, $class; }
I tend to use shift
when there is one argument or when I want to treat the first few arguments differently than the rest.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With