Wakan Tanka
Wakan Tanka

Reputation: 8042

Perl - argument passing for function as function argument - nice and clear way

Hello I have function to which I am passing arguments using hash, this way:

&group_AoA_to_HoA_by_AoAs_columns({
    AoA          => \@group_file_by_line_numbers_AoA,
    HoA          => \%group_file_by_group_names_HoA,
    key_index    => 0,
    columns      => "ALL",
    save_method  => \&append_or_overwrite,
    action       => "ADD"
});

In this function I am accessing passed variables this way:

my $AoA         = $args->{"AoA"};
my $HoA         = $args->{"HoA"};
my $key_index   = $args->{"key_index"};
my $columns     = $args->{"columns"};
my $save_method = $args->{"save_method"};
my $action      = $args->{"action"};

Argument "save_method" is name of another function (passed as argument to group_AoA_to_HoA_by_AoAs_columns function). This Function is also called (from group_AoA_to_HoA_by_AoAs_columns function) with some passed arguments:

$save_method->({
    action     => $action,
    position   => \$HoA->{ $array->[$key_index] },
    data       => [@selected_columns],
});

The argument "action" is passed first time for "group_AoA_to_HoA_by_AoAs_columns" function and second time to function which "save_method" is referring to. There is no other reason for this argument.

So finally my question is if it possible to rewrite this code to more uniform equivalent from which will be immediately clear that "action" parameter is only used by function which "save_method" is referring to? Something like this would be fine:

&group_AoA_to_HoA_by_AoAs_columns({
    AoA          => \@group_file_by_line_numbers_AoA,
    HoA          => \%group_file_by_group_names_HoA,
    key_index    => 0,
    columns      => "ALL",
    save_method  => \&append_or_overwrite({
                          action       => "ADD"
    })
});

Upvotes: 1

Views: 94

Answers (2)

Michael Carman
Michael Carman

Reputation: 30831

One option is to wrap the reference to your save method in an anonymous subroutine that provides any static arguments:

save_method => sub { append_or_overwrite({ action => 'ADD', %{shift()}}) },

The %{shift()} allows you to specify any additional arguments using the same pass-a-hashref convention that you do at present:

$save_method->({
    position => \$HoA->{ $array->[$key_index] },
    data     => [@selected_columns],
});

An alternate approach would be to specify the save method using an array reference where the first value is a CODE reference and any additional values are arguments to it.

save_method => [\&append_or_overwrite, action => 'ADD'],

Invoke it as:

my ($code, @args) = @$save_method;
$code->({
    position => \$HoA->{ $array->[$key_index] },
    data     => [@selected_columns],
    @args,
});

Tangent: Passing the save method data as [@selected_columns] creates a (shallow) copy. If you don't need a copy (because the save method doesn't modify it) it's better to write \@selected_columns to pass a reference to the original array. Similarly, I'm not sure why you're passing position via \$HoA->{ $array->[$key_index] } which appears to be a reference to an array reference instead of passing it the array reference directly as $HoA->{ $array->[$key_index] }.

Upvotes: 3

mpapec
mpapec

Reputation: 50637

You can use anonymous function if you want call append_or_overwrite with specified parameter,

save_method  => sub {
  # 'return' is optional
  return append_or_overwrite({
                      action       => "ADD"
  })
}

Upvotes: 4

Related Questions