Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is 'shift' evil for processing Perl subroutine parameters?

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?

like image 499
Nikolai Prokoschenko Avatar asked Aug 25 '09 13:08

Nikolai Prokoschenko


People also ask

What is the use of shift in Perl subroutine?

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.

How do you pass arguments in Perl subroutine?

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.

What is the difference between shift and @_ used in passing arguments to subroutine?

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.

Why should you pass parameters to subroutines?

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.


2 Answers

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.

like image 141
John Siracusa Avatar answered Sep 19 '22 15:09

John Siracusa


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.

like image 29
Chas. Owens Avatar answered Sep 20 '22 15:09

Chas. Owens