Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Perl support named parameters in function calls?

In my experience of languages that support the feature, programs that call functions with named parameters rather than positional parameters are easier to read and maintain.

I think Perl has this feature, but it's not working for me.

Is it a quirk of the package I'm using, or am I doing it wrong?

Setting up the function call

My fist Perl project is to use the HTML::TableExtract package to extract table data from HTML markup and display it as text.

The following code sets up the parser:

use strict;
use warnings;
use HTML::TableExtract;

my $markup = <<MARKUP;
<table>
  <tr> <th>a</th> <th>b</th> <th>c</th> </tr>
  <tr> <td>1</td> <td>2</td> <td>3</td> </tr>
  <tr> <td>4</td> <td>5</td> <td>6</td> </tr>
</table>
MARKUP

my $parser = HTML::TableExtract->new() ;

$parser->parse($markup) ;

The documentation says that I can dump output to the Command Prompt using the tables_dump method and use parameters $show_content and $col_sep to control the output format:

tables_report([$show_content, $col_sep])

Return a string summarizing extracted tables, along with their depth and count. Optionally takes a $show_content flag which will dump the extracted contents of each table as well with columns separated by $col_sep. Default $col_sep is ':'.

tables_dump([$show_content, $col_sep])

Same as tables_report() except dump the information to STDOUT.

Calling with positional and with named parameters

If I pass positional parameters in documentation order, I get the output I expect:

$parser->tables_dump(1, '_') ;

The columns are separated by an underscore instead of the default colon:

TABLE(0, 0):
a_b_c
1_2_3
4_5_6

Following Perl.com's Advance Subroutines article, I tried to pass a hash containing parameter names and values to clarify the meaning of the parameters:

$parser->tables_dump({show_content => 1, col_sep => '_'}) ;

Perl doesn't understand this. It ignores the value of col_sep and outputs with the default value:

TABLE(0, 0):
a:b:c
1:2:3
4:5:6

I get the same output if I don't try to change the separator:

$parser->tables_dump({show_content => 1}) ;

Even if I specify nonsense parameter names, I get the same output:

$parser->tables_dump({tweedledum => 1, tweedledee => '_'}) ;

Can I call this function using the named parameter style, or should I just settle for positional?

like image 263
Iain Samuel McLean Elder Avatar asked Nov 26 '12 02:11

Iain Samuel McLean Elder


People also ask

How do you pass a function parameter in Perl?

You can pass various arguments to a Perl subroutine like you do in any other programming language and they can be accessed inside the function using the special array @_. Thus the first argument to the function is in [0],thesecondisin_[1], and so on.

Does Perl pass by value or reference?

Perl always passes by reference. It's just that sometimes the caller passes temporary scalars. Perl passes by reference. Specifically, Perl aliases each of the arguments to the elements of @_ .

Why is it a good idea to use named parameters instead of the syntax?

With named parameters, it is usually possible to provide the values in any arbitrary order, since the name attached to each value identifies its purpose. This reduces the connascence between parts of the program. A few languages use named parameters but still require the parameters to be provided in a specific order.

Why do we use named parameters?

Create a function which takes in a number of arguments which are specified by name rather than (necessarily) position, and show how to call the function. If the language supports reordering the arguments or optionally omitting some of them, note this.


2 Answers

Perl doesn't natively support named parameters, however it's possible to design functions to accept named parameters (as a hash or hashref). It's up to the author of the function as to how they implement it. You'll need to supply arguments the function is expecting or you'll get unexpected results.

like image 187
Seganku Avatar answered Sep 28 '22 06:09

Seganku


Named parameter passing in Perl (even with default values) is explained very well in Object Oriented Perl, Chapter 6. This style is very important and is widely used in object constructors. That's why it is explained in their OO Perl book.

I will quote two of their examples:

# This is how you call a subroutine using named argument passing
interests(name => "Paul", language => "Perl", favourite_show => "Buffy");

# This is how you define the subroutine to accept named arguments
sub interests {
   my (%args) = @_;

   # This is how you capture named arguments and define
   # defaults for the ones missing from a particular call.
   my $name           = $args{name}           || "Bob the Builder";
   my $language       = $args{language}       || "none that we know";
   my $favourite_show = $args{favourite_show} || "the ABC News";

   print "${name}’s primary language is $language. " .
   "$name spends their free time watching $favourite_show\n";
}

Another example that gives a different way of defining defaults (in a hash) is this:

my %defaults = ( pager => "/usr/bin/less", editor => "/usr/bin/vim" );

sub set_editing_tools {
    my (%args) = @_;

    # Here we join our arguments with our defaults. Since when
    # building a hash it’s only the last occurrence of a key that
    # matters, our arguments will override our defaults.
    %args = (%defaults, %args);

    # print out the pager:
    print "The new text pager is: $args{pager}\n";

    # print out the editor:
    print "The new text editor is: $args{editor}\n";
}
like image 34
Ahmed Nassar Avatar answered Sep 28 '22 07:09

Ahmed Nassar