gcbenison gcbenison - 4 months ago 10
Perl Question

Reusable, abstracted way to bind multiple lexicals all in one go

I have code that repeats this pattern:

sub method1 {
my ($foo, $bar) = _get_things(); # this line...
}

sub method2 {
my ($foo, $bar) = _get_things(); # ...is repeated here
}


The repeated line is just one line, so in a sense repeating it is no big deal. But, that has the drawback that if the list
($foo, $bar)
ever changes, all these lines need to change. In C, one might use the preprocessor to solve this problem. Is there a good idiom for doing it in Perl? Something like the following psuedo-perl:

MACRO_DEFINITION my ($foo, $bar) = _get_things();

sub method1 {
MACRO_CALL
print "hi $foo";
}

sub method2 {
MACRO_CALL
print "hi $foo and $bar";
}


note: the reason
_get_things()
returns a list that I am binding to local lexical scalars is that I want to use them in string interpolation, as the latter example shows.

Answer

When a sub has more than a very few parameters, or what the parameters are is possibly going to change, you should pass a hash or hashref to emulate named parameters.

All the more so here, where you are returning more than one result and what the results are is likely to change, you should return a hashref from the sub. And just use that hashref in the caller (yes, even in string interpolation.)

use strict;
use warnings;

sub method2 {
    my $thing = _get_things();
    print "hi $thing->{'foo'} and $thing->{'bar'}\n";
}

sub _get_things {
    return {
        'foo' => 42,
        'bar' => 'quux',
    };
}

method2();