Making Sense of Subroutines
by Rob Kinyon
|
Pages: 1, 2, 3, 4
Dispatch Tables
Often, you need to call a specific subroutine based some user input. The first attempts to do this usually look like this:
if ( $input eq 'foo' ) {
foo( @params );
}
elsif ( $input eq 'bar' ) {
bar( @params );
}
else {
die "Cannot find the subroutine '$input'\n";
}
Then, some enterprising soul learns about soft references and tries something like this:
&{ $input }( @params );
That's unsafe, because you don't know what $input will to contain. You cannot guarantee anything about it, even with taint and all that jazz on. It's much safer just to use dispatch tables:
my %dispatch = (
foo => sub { ... },
bar => \&bar,
);
if ( exists $dispatch{ $input } ) {
$dispatch{ $input }->( @params );
}
else {
die "Cannot find the subroutine '$input'\n";
}
Adding and removing available subroutines is simpler than the if-elsif-else scenario, and this is much safer than the soft references scenario. It's the best of both worlds.
Subroutine Factories
Often, you will have many subroutines that look very similar. You might have accessors for an object that differ only in which attribute they access. Alternately, you might have a group of mathematical functions that differ only in the constants they use.
sub make_multiplier {
my ($multiplier) = @_;
return sub {
my ($value) = @_;
return $value * $multiplier;
};
}
my $times_two = make_multiplier( 2 );
my $times_four = make_multiplier( 4 );
print $times_two->( 6 ), "\n";
print $times_four->( 3 ), "\n";
----
12
12
Try that code and see what it does. You should see the values below the dotted line.
Conclusion
Subroutines are arguably the most powerful tool in a programmer's toolbox. They provide the ability to reuse sections of code, validate those sections, and create new algorithms that solve problems in novel ways. They will reduce the amount of time you spend programming, yet allow you to do more in that time. They will reduce the number of bugs in your code ten-fold, and allow other people to work with you while feeling safe about it. They truly are programming's super-tool.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 5 of 5.
- Good article about subroutines
2006-06-16 22:45:21 leed25d [Reply]
but, hey, *lousy* gustatorial sense. Peanut butter and banana on Wonder bread is probably one of the best sandwiches ever conceived.
- Excellent Article
2005-12-07 15:28:05 matt.follett [Reply]
I've been learning Perl for a little bit of time now and this actually answered a few of my "I'm sure there is a better way to do this, but I don't know it" concerns.
- Recursion Subroutine
2005-11-07 04:11:12 IllvilJa [Reply]
Good article!
Perhaps the subroutine $_recurse() defined in the code listing under the section "Recursion" should have been a complete piece of code and not just skeleton, to provide a clearer demonstration of the concept of a recursive inner subroutine. The actual computation should of course not be anything fancy (the simpler the better) as long as it is a recursive computation.
Of course, as you mentioned in your previous answer, your article is limited in size, something that could prevent you from making the subroutine complete.
Maybe a topic for yet another follow up on this article?
Best regards
/IllvilJa
- named args
2005-11-06 09:37:35 matijapapec [Reply]
Good article imho, but when writing about subroutines it might be good to mentions named arguments also
sub foo {
my %arg = (%default_args, @_);
...
}
- named args
2005-11-06 11:21:35 RobKinyon [Reply]
Thank you for the reply! I appreciate you taking the time to read the article.
I thought about named arguments and chose tot to include them. One concern was space - I only have so many words per article. The real argument was that named arguments (and other items) really deserve their own article, which could be considered a followup to this article. Those other items in such an article would include:
* Hashes for named arguments and why hashrefs are better
* Usage of Params::Validate and friends
* How to handle optional arguments (with and without defaults)
* When Perl prototypes are appropriate
* wantarray and other contextual items
* Subroutines that modify their parameters
* Well-written methods and how to enforce a private or protected method in Perl
* Redispatching based on subroutine signature (a la Perl6 or CLOS)
It's more than just named arguments. :-)
- named args



