2006-02-25

Neat Perl Trick

A nice Perl feature that I gleaned from reading Advanced Subroutine Techniques over at Perl.com is that you can pass a hash of values to a subroutine instead of an ordered list of values.

Let me explain. No, there is too much to explain. Let me sum up.

The way that Perl is taught to the youngsters is that if you call a sub by typing &my_sub($apple, $broccoli, $carrot), then Perl, in its infinite wisdom, will take $apple, $broccoli, and $carrot and put them into a magical array called "@_". @_ is called the argument list, and you can do a few neat things with it. Usually, you have a line at the start of my_sub that looks like this:

  my ($x, $y, $z) = @_

That turns the locally scoped variable $x into what you have for $apple. $y gets $broccoli, and $z gets $carrot. Downsides? You have a static number of variables, so you can only ever use &my_sub() with three arguments in one defined ordering. &my_sub(1, 2, 3), for instance, is an entirely different beast than &my_sub(2, 3, 1).

You could loop through your args with some logic built around a "shift @_" statement. That works pretty well when you don't know or don't care how many args you've got and you want them all to be treated similarly. "shift @_" is perfect for things like "my $sum = &add_the_following(1,2,3,4,5) + &add_the_following(6,7,8,9)".

This is a perfectly serviceable means by which to use Perl's subroutines, and these were the only tools in my arsenal until today. Fortunately, now I know how one can, with a good bit more typing, create damned easy to maintain subroutines. Since this is Perl, after all, it involves using hashes.

Instead of passing the list of "$apple, $broccoli, $carrot", you pass a self-documenting hash object:

&my_sub({
           my_favorite_fruit        => $apple,
           my_least_favorite_veggie => $broccoli,
           something_orange         => $carrot,
});

Now, you don't do "my ($x, $y, $z) = @_". You do "my ($args) = @_" and grab the argument you've titled accordingly:

if (exists $args->{ something_orange }) {
  print $args->{ something_orange });
}

Though this results in a good bit more typing than usual, it also will make the code you write today easier to understand a year from now, and Perl needs all the help in that department that it can get.

No comments: