2.1 The Cure for the Common Code
Let's say a famous
sailor (we'll call him "the
Skipper") uses Perl to help navigate his ocean-going
vessel (call it "the Minnow"). The
Skipper writes many Perl programs to provide navigation for all the
common ports of call for the Minnow. He finds himself cutting and
pasting a very common routine into each program:
sub turn_towards_heading {
my $new_heading = shift;
my $current_heading = current_heading( );
print "Current heading is ", $current_heading, ".\n";
print "Come about to $new_heading ";
my $direction = "right";
my $turn = ($new_heading - $current_heading) % 360;
if ($turn > 180) { # long way around
$turn = 360 - $turn;
$direction = "left";
}
print "by turning $direction $turn degrees.\n";
}
This routine gives the shortest turn to make from the current heading
(returned by the subroutine current_heading( )) to
a new heading (given as the first parameter to the subroutine).
The first line of this subroutine might have read instead:
my ($new_heading) = @_;
This is mostly a style call: in both
cases, the first parameter ends up in
$new_heading. However, in later chapters,
you'll see that removing the items from
@_ as they are identified does have some
advantages. So, this book sticks (mostly) with the
"shifting" style of argument
parsing. Now back to the matter at hand...
Suppose that after having written a dozen programs using this
routine, the Skipper realizes that the output is excessively chatty
when he's already taken the time to steer the proper
course (or perhaps simply started drifting in the proper direction).
After all, if the current heading is 234 degrees and he needs to turn
to 234 degrees, you see:
Current heading is 234.
Come about to 234 by turning right 0 degrees.
How annoying! The Skipper decides to fix this problem by checking for
a zero turn value:
sub turn_towards_heading {
my $new_heading = shift;
my $current_heading = current_heading( );
print "Current heading is ", $current_heading, ".\n";
my $direction = "right";
my $turn = ($new_heading - $current_heading) % 360;
unless ($turn) {
print "On course (good job!).\n";
return;
}
print "Come about to $new_heading ";
if ($turn > 180) { # long way around
$turn = 360 - $turn;
$direction = "left";
}
print "by turning $direction $turn degrees.\n";
}
Great. The new subroutine works nicely in the current navigation
program. However, because it had previously been cut-and-pasted into
a half dozen other navigation programs, those other programs will
still annoy the Skipper with extraneous turning messages.
You need a way to write the code in one place and then share it among
many programs. And like most things in Perl, there's
more than one way to do it.
|