Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify default values for optional subroutine arguments?

Tags:

perl

Is there an elegant way to specify default values for subroutine arguments?

Currently, I am using the following approach:

use strict;
use warnings;

func1( "arg1", "arg2", opt1 => "first option", opt2 => 0 );

sub func1 {
    my ( $arg1, $arg2, %opt ) = @_;

    $opt{opt1} //= "no option";
    $opt{opt2} //= 1;
    $opt{opt3} //= [];
}

which looks a little bit ugly, when there are many options. I would rather like to do

sub func2 {
    my ( $arg1, $arg2, $opt ) = process_args( 
        opt1 => "no option", opt2 => 1, opt3 => []
    );
}

The best I could come up with for this approach was:

sub func2 {
    my ( $arg1, $arg2, $opt ) = process_args(
        \@_, 2, opt1 => "no option", opt2 => 1, opt3 => []
    );
}

sub process_args {
    my ($a, $n, %opt_info ) = @_;

    my @b = splice @$a, 0, $n;
    my %opt = @$a;
    for my $key (keys %opt_info) {
        $opt{$key} //= $opt_info{$key};
    }
    return (@b, \%opt);
}

but now I got the other problem, that I must pass \@_ and the number of non-option arguments ( here 2 ), to process_args..

like image 869
Håkon Hægland Avatar asked Jun 03 '26 18:06

Håkon Hægland


2 Answers

sub func1 {
    my $arg1 = shift;
    my $arg2 = shift;
    my %opt = (
       opt1 => 'default',
       opt2 => 'default',
       @_
    );

Or, you can use Params::Validate.

like image 51
Sinan Ünür Avatar answered Jun 05 '26 13:06

Sinan Ünür


I don't remember seeing a subroutine written expressly to handle subroutine parameters. Do you have a Ruby background?

You can define the options hash by a list of its defaults, followed by anything passed in @_. Like this

use strict;
use warnings;

func1( "arg1", "arg2", opt1 => "first option", opt2 => 0 );

sub func1 {
  my ( $arg1, $arg2 ) = splice @_, 0, 2;
  my %opts = (
    opt1 => "no option",
    opt2 => 1,
    opt3 => [],
    @_,
  );
}

Another mechanism, if you want to warn against unsupported paremeters, is to do much as you have, but use delete, and to ensure that the hash is empty afterwards, like this

use strict;
use warnings;

use Data::Dump;
use Carp 'croak';

func1( "arg1", "arg2", opt9 => 9 );

sub func1 {
  my ( $arg1, $arg2, %opt ) = @_;

  my $opt1 = delete $opt{opt1} // 'no option';
  my $opt2 = delete $opt{opt2} // 1;
  my $opt3 = delete $opt{opt3} // [];

  croak "Unexpected parameters: ", join ',', keys %opt if keys %opt;
}

output

Unexpected parameters: opt9 at E:\Perl\source\args.pl line 16.
  main::func1("arg1", "arg2", "opt9", 9) called at E:\Perl\source\args.pl line 7
like image 42
Borodin Avatar answered Jun 05 '26 14:06

Borodin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!