Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameters passing style in Perl

I see people using two styles for passing named parameters in Perl:

use strict;
use warnings;
use Data::Dumper;

sub foo {
    print Dumper @_;
}

sub bar {
    print Dumper @_;
}

foo( A => 'a', B => 'b' );
bar( { A => 'a', B => 'b' } );

What are the advantages in using foo() style instead of bar() style?

like image 341
Howard Avatar asked Jul 30 '10 10:07

Howard


3 Answers

The second method passes a reference to hash, while the first just passes a list.

There are two aspects here: in theory, a reference to hash could be better in terms of performance, though for short argument lists this is negligible. For a simple call like foo(a => 1, b => 2) there is no performance difference, because @_ is actually an alias to the original values.

But if the caller already has the values in a hash, the first style requires conversion from hash to list, and then back again to hash, which can be slow.

The second aspect is the question who is responsible for the conversion to a hash. The first style leaves it up the function being called, and if that just does my %args = @_, it will produce curious warnings if the argument list is not of even length.

That's why I slightly prefer the second style (or I use Perl 6, which supports named arguments natively).

like image 126
moritz Avatar answered Oct 19 '22 23:10

moritz


The foo(a => 1, b => 2) style is the usual way of emulating named arguments. The bar({a => 1, b => 2}) is usually used only for supplementary (and possibly optional) arguments.

For typical usage, I prefer the first form. The {} are extra typing, extra noise to read, and create a possible error if you leave out either or both braces. Any performance difference is negligible. (If it's not, you have bigger problems.) On the other hand, wrapping the arguments in an anonymous hash constructor can help you find errors at compile-time rather than runtime.

The second form is typically seen mixed with positional arguments. e.g. Benchmark does this:

cmpthese(10000, {
    foo => \&foo,
    bar => \&bar,
});

While Tk leaves the {} out:

my $text = $w->Scrolled('Text', -width => 80, -height => 50);

It's usually a stylistic choice.

like image 22
Michael Carman Avatar answered Oct 20 '22 00:10

Michael Carman


First, an explanation of the two methods:

sub foo {
    # Transform the array to a hash
    my %args = @_;

    foreach my $key ( keys %args ) {
        print "$key => $args{$key}\n";
    }
}

# Pass an array of values
foo( A=>'a', B=>'b' );

In this first case all you're doing is passing an array. The => in this context is not the hash key / value indicator which you might think. In this context it's just a "fat comma".

sub bar {
    my ($hash_ref) = @_;
    foreach my $key ( keys %$hash_ref ) {
        print "$key => $hash_ref->{$key}\n";
    }
}

# pass a ref to an anonymous hash
bar( { A=>'a', B=>'b' } );

In this second case you are creating an anonymous hash and passing a reference to that hash as the argument to the function.

Why choose one over the other? In the book, Perl Best Practices, chapter 9 under the heading "Named Arguments" the author recommends using the second style when there are more than three arguments to the function. He also prefers it because it catches mismatched numbers of arguments at compile time rather than at run time.

like image 33
Robert S. Barnes Avatar answered Oct 19 '22 22:10

Robert S. Barnes