Search code examples
perlnamed-parameters

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?


Solution

  • 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:

    That article covers a way to write subroutines such that they will accept a hashref of named parameters. If you're calling a sub that isn't written to accept that, then it won't know how to handle it correctly.

    $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:

    Not to be overly pedantic, but Perl understands that just fine. However, tables_dump is only written to accept a list of scalar parameters. When you call it that way, it receives a single scalar parameter. This parameter just happens to be a reference to a hash, but tables_dump doesn't know or care about that, so it uses the reference as the value of $show_content. This is probably equivalent to passing 1 for show_content, since both 1 and any possible reference will evaluate as "true" in boolean context and I assume that $show_content is only ever used as a boolean.

    Since there is no second parameter, nothing gets assigned to $col_sep, so it uses the default separator, as you observed.