Advanced Subroutine Techniques
by Rob KinyonFebruary 23, 2006
In "Making Sense of Subroutines," I wrote about what subroutines are and why you want to use them. This article expands on that topic, discussing some of the more common techniques for subroutines to make them even more useful.
Several of these techniques are advanced, but you can use each one by itself without understanding the others. Furthermore, not every technique is useful in every situation. As with all techniques, consider these as tools in your toolbox, not things you have to do every time you open your editor.
Named Arguments
Positional Arguments
Subroutines, by default, use "positional arguments." This means that the arguments to the subroutine must occur in a specific order. For subroutines with a small argument list (three or fewer items), this isn't a problem.
sub pretty_print {
my ($filename, $text, $text_width) = @_;
# Format $text to $text_width somehow.
open my $fh, '>', $filename
or die "Cannot open '$filename' for writing: $!\n";
print $fh $text;
close $fh;
return;
}
pretty_print( 'filename', $long_text, 80 );
The Problem
However, once everyone starts using your subroutine, it starts expanding what it can do. Argument lists tend to expand, making it harder and harder to remember the order of arguments.
sub pretty_print {
my (
$filename, $text, $text_width, $justification, $indent,
$sentence_lead
) = @_;
# Format $text to $text_width somehow. If $justification is set, justify
# appropriately. If $indent is set, indent the first line by one tab. If
# $sentence_lead is set, make sure all sentences start with two spaces.
open my $fh, '>', $filename
or die "Cannot open '$filename' for writing: $!\n";
print $fh $text;
close $fh;
return;
}
pretty_print( 'filename', $long_text, 80, 'full', undef, 1 );
Quick--what does that 1 at the end of the subroutine mean? If it took you more than five seconds to figure it out, then the subroutine call is unmaintainable. Now, imagine that the subroutine isn't right there, isn't documented or commented, and was written by someone who is quitting next week.
The Solution
The most maintainable solution is to use "named arguments." In Perl 5, the best way to implement this is by using a hash reference. Hashes also work, but they require additional work on the part of the subroutine author to verify that the argument list is even. A hashref makes any unmatched keys immediately obvious as a compile error.
sub pretty_print {
my ($args) = @_;
# Format $args->{text} to $args->{text_width} somehow.
# If $args->{justification} is set, justify appropriately.
# If $args->{indent} is set, indent the first line by one tab.
# If $args->{sentence_lead} is set, make sure all sentences start with
# two spaces.
open my $fh, '>', $args->{filename}
or die "Cannot open '$args->{filename}' for writing: $!\n";
print $fh $args->{text};
close $fh;
return;
}
pretty_print({
filename => 'filename',
text => $long_text,
text_width => 80,
justification => 'full',
sentence_lead => 1,
});
Now, the reader can immediately see exactly what the call to pretty_print() is doing.
And Optional Arguments
By using named arguments, you gain the benefit that some or all of your arguments can be optional without forcing our users to put undef in all of the positions they don't want to specify.
Pages: 1, 2 |


