develooper Front page | perl.beginners | Postings from May 2012

Re: shift vs @_

Thread Previous | Thread Next
From:
David Christensen
Date:
May 20, 2012 15:15
Subject:
Re: shift vs @_
Message ID:
4FB96CE8.4070706@holgerdanske.com
On 05/20/2012 08:09 AM, sono-io wrote:
> 	Are there any differences between these two idioms if only one or zero arguments are passed to them?
> my ($mode) = @_;
> my $mode = shift;


If your subroutine needs to know how many arguments were passed, the 
former style (assignment) makes this trivial.  Once @_ has been shifted 
(latter style), I don't know an easy way to determine if zero or one 
argument was passed (stack crawling?).


But, this is Perl and there are more than two ways to do it -- you can 
also access the argument array (@_) directly within your subroutine:

1.  Might save some CPU cycles and/or memory.  Be sure to benchmark this 
claim, to see if it's worth the loss of clarity provided by well-named 
internal variables.

2.  Provides call-by-reference semantics -- your subroutine can modify 
the caller's variables (intentionally or otherwise -- beware!).

3.  Auto-vivifies missing arguments (?).

4.  Blows up if the subroutine tries to modify read-only arguments.


I started using this technique for #1, but soon tripped over the risks 
of #2.  I'm not sure if I was aware of #3 and #4 prior to writing the 
test code, below.


I also tried testing functions with array arguments -- changing elements 
(yes, that works) and changing the array length (I got confused).


I concur with Rob's advice for object methods:

On 05/20/2012 08:30 AM, Rob Dixon wrote:
 >    my $self = shift;
 >    my ($arg1, $arg2) = @_;


Note that Moose around method modifiers use a shift, shift, assignment 
style.


As always, there is no single best approach for all cases:

1.  Do what makes sense when you write the code, and

2.  Try to be consistent so that it is easier to debug and maintain the 
code later.


HTH,

David

--

2012-05-20 14:08:47 dpchrist@p43400e ~/sandbox/perl
$ cat function_arguments.pl
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Terse = 1;
$| = 1;
sub f_assign {
     my ($a) = @_;
     $a += 1;
}
sub f_direct {
     $_[0] += 1;
}
sub f_shift {
     my $a = shift;
     $a += 1;
}
# main
{
     for my $f (qw( f_assign f_shift f_direct )) {
	my $y = eval { no strict 'refs'; $f->() };
	print "$f() ", $@
	    ? "throws exception: $@"
	    : 'returns ' . Data::Dumper->Dump([$y], [qw(y)]);
	$y = eval { no strict 'refs'; $f->(10) };
	print "$f(10) ", $@
	    ? "throws exception: $@"
	    : 'returns ' . Data::Dumper->Dump([$y], [qw(y)]);
	my $xx = my $x = 100;
	print '$x = ', Data::Dumper->Dump([$x], [qw(x)]);
	$y = eval { no strict 'refs'; $f->($x) };
	print "$f(\$x) ", $@
	    ? "throws exception: $@"
	    : 'returns ' . Data::Dumper->Dump([$y], [qw(y)]);
	print '### side effect: $x is now ',
	    Data::Dumper->Dump([$x], [qw(x)])
	    if $x != $xx;
     }
}

2012-05-20 14:08:49 dpchrist@p43400e ~/sandbox/perl
$ perl function_arguments.pl
f_assign() returns 1
f_assign(10) returns 11
$x = 100
f_assign($x) returns 101
f_shift() returns 1
f_shift(10) returns 11
$x = 100
f_shift($x) returns 101
f_direct() returns 1
f_direct(10) throws exception: Modification of a read-only value 
attempted at function_arguments.pl line 12.
$x = 100
f_direct($x) returns 101
### side effect: $x is now 101

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About