An unexpected benefit of thinking functional in Perl
I’ve been reading more and more about functional programming over the past year, and working in Python where many things are immutable, and I’m trying to incorporate them into my Perl code.
Probably the biggest influence of functional is that I try to call as few verbs as possible. For example, here’s some code from my codebase at work.
my @got;
push(@got, 'books') if ($list->bwanted > 0);
push(@got, 'eBooks') if ($list->ewanted > 0 and $user->can_order_ebooks eq 'Y');
push(@got, 'A/V items') if ($list->awanted > 0);
That’s three different calls to push
in three lines of code that are very
similar to each other. We shouldn’t need to do that.
The pattern here is that we push the string on the left into @got
if the
condition on the right is true. I created a function called map_x_if_y
to handle this, letting me rewrite the lines above as:
my @got = map_x_if_y(
'books' => ($list->bwanted > 0),
'eBooks' => ($list->ewanted > 0 and $user->can_order_ebooks eq 'Y'),
'A/V items' => ($list->awanted > 0),
);
Now I have no instances of push
, and I’m just declaring conditions and
results. Any work being done is hidden inside a function. I’m only
setting the contents of @got
one time, and the focus is on the data.
The function itself is very simple:
use List::Util qw( pairmap );
sub map_x_if_y {
return pairmap { $b ? ($a) : () } @_
}
I’m not very happy with the name map_x_if_y
. Please email me if you have
ideas for a better name, or if there’s a standard name for this operation.
I was happy with this refactoring, but then it got better. When I ran the
perlcritic
code analyzer
on the original .pm file, I was helpfully informed that “@got is declared
but not used at line…” The only code that’s better than cleaned-up code
is code that I can throw away!
I got the new message because I had the
Variables::ProhibitUnusedVarsStricter
policy installed, and since there was now only one place where @got
was
being referenced, the policy knew that it was not being used.
Another win for thinking functional, and another win for running
perlcritic
often.