the_Don has asked for the wisdom of the Perl Monks concerning the following question:
I have seen two different methods of assigning my-type variables from passed in arguments. The two ways I am talking about is shown below:
sub routine1 {
my ($var_one, $var_two, $var_three) = @_;
...
}
sub routine2{
my $var_one = shift;
my $var_two = shift;
my $var_three = shift;
...
}
So, my question is "What are the benefits, drawbacks relating to performance of the two ways, if any?" I know that shift reduces the array by one, and then the leftovers are typically used in loops, etc... I have not been able to see anything that explains any other difference, so are the two methods relatively equal in execution time, and therefore the ultimate decision is preference of the coder?
the_Don
...making offers others can't rufuse.
Re: Argument Passing, preference or performance ?
by dws (Chancellor) on Nov 11, 2002 at 21:50 UTC
|
... so are the two methods relatively equal in execution time, and therefore the ultimate decision is preference of the coder?
For 99% of what I do, clarity outweights performance considerations. So for clarity, I've adopted the following conventions:
- For object methods, always shift $self, and use array assignment to put any remaining arguments into variables. The shift becomes a visual clue that the sub is an object method.
- For constructors, I always shift the package name. If I'm interested in any additional arguments, I use array assignment to put them into variables. Typically, though, any arguments are a hash to initialize an instance.
- For non-object methods, use array assignment.
This leads to code that looks like:
sub new {
my $pkg = shift;
bless { default => 1, @_ }, $pkg;
# @_ might override 'default'
}
sub method {
my $self = shift;
my($shoesize) = @_;
....
}
my non_method {
my($height, $width) = @_;
...
}
Code that's consistently written is easier to read, and code that's easier to read is easier to optimize. YMMV, or course.
| [reply] [d/l] |
Re: Argument Passing, preference or performance ?
by tye (Sage) on Nov 11, 2002 at 21:34 UTC
|
As I said in the CB when you asked, see Shift versus Sanity.
"Performance"?? Why is that a concern??
- tye (optimize only after profiling; profile only if needed)
| [reply] |
Re: Argument Passing, preference or performance ?
by Wonko the sane (Deacon) on Nov 11, 2002 at 21:52 UTC
|
I agree with tye, though personally I prefer to use the
my ( $var_one, $var_two ) = @_;
type syntax. I find it easier to read, takes up less space
(hate scrolling continually just to see complete routine)
and it leaves the initial arguement array untouched.
Really just my personal preference,.. though intuition tells me that an array assignment
would possibly be less resource intensive than a bunch of repeated shift calls.
Though neither would probably make a big difference in your program.
Your time would probably be better spend playing with Devel::Dprof
and finding out what areas of your program really need to be optimized.
Best Regards,
Wonko
| [reply] [d/l] |
Re: Argument Passing, preference or performance ?
by Anonymous Monk on Nov 11, 2002 at 22:44 UTC
|
Logically they are the same, and even the gracefulness are the same. However there is one situation, I would suggest to use @_ instead of shift, to provide the elegance. That's the time you pass named parms, for example:
sub func {
%parms = @_;
foreach (keys %parms) {
print "parms[$_] = $parms{$_}\n";
}
}
func("a" => 1, "b" => 2, "c" => 3);
Well, you can use shift, but in this case, a little bit tasteless, is it?
| [reply] [d/l] |
|
sub Open {
my( $file, $opts )= @_;
foreach $key ( %$opts ) {
# ...
}
}
Open( "file", { ReadOnly=>1, Retries=>2 } );
for the following reasons:
- It leaves lots of room for flexability in the API. For example, if my routine requires a 'file' parameter, then I don't see much point in requiring you to type File => when I can do things as above. You can even have optional parameters:
sub Open {
my $opts= UNIVERSAL::isa( $_[-1], "HASH" )
? pop(@_) : {};
my( $file, $mode, $mask )= @_;
# ...
}
Open( "file" );
Open( "file", { Exclusive=> 1 } );
Open( "file", "w", 0666, { Locked=>1 } );
- The "Odd number of elements in hash assignment" warning automatically gets thrown at the calling code where it belongs
- It provides a visual cue that named arguments are being used
- It stops you from getting tricky and doing:
Create( Name=>"This", Users=>'fred','bob','joe' );
which you will regret later. Instead you are forced to:
Create( Name=>"This", Users=>['fred','bob','joe'] );
But you need to be careful to not have your function modify the hash. (:
- tye | [reply] [d/l] [select] |
|
I'm not sure I agree that the gracefulness is the same. One situation that comes to mind is when you want to populate the elements of a hash with the passed arguments:
sub add_person {
my %person = ();
@person{qw(firstname lastname addr1 addr2 city state zip)} = @_;
...
}
vs.
sub add_person {
my %person = ();
$person{firstname} = shift;
$person{lastname} = shift;
$person{addr1} = shift;
$person{addr2} = shift;
$person{city} = shift;
$person{state} = shift;
$person{zip} = shift;
...
}
The first one just seems a lot cleaner to me. (Of course, in practice you might have the list of field names in a predefined array that you could loop through, but you get the idea.)
--Kevin | [reply] [d/l] [select] |
|
Logically they are the same
Unfortunately not. routine1 makes the assignment without modifying @_, whereas routine2 consumes elements of @_. Add something like return $_[0]; to each of the above and in general you will get different results...
$perlmonks{seattlejohn} = 'John Clyman';
| [reply] [d/l] |
Re: Argument Passing, preference or performance ?
by Ananda (Pilgrim) on Nov 12, 2002 at 11:00 UTC
|
tye's got the reasoning, there is actually not much difference in the two methods, its better to use these methods for better readability.
As far as performance is concerned it really doesnt matter.
It is upto the coder to decide what/how to present by way of coding.
Anandatirtha
| [reply] |
Re: Argument Passing, preference or performance ?
by pg (Canon) on Nov 11, 2002 at 22:46 UTC
|
(Forgot to login first, :-)
Logically they are the same, and even the gracefulness are the same. However there is one situation, I would suggest to use @_ instead of shift, to provide the elegance. That's the time you pass named parms, for example:
sub func {
%parms = @_;
foreach (keys %parms) {
print "parms[$_] = $parms{$_}\n";
}
}
func("a" => 1, "b" => 2, "c" => 3);
Well, you can use shift, but in this case, a little bit tasteless, is it? | [reply] [d/l] |
|
|