By Randal L. Schwartz
With
Tom Phoenix
Cover | Table of Contents | Colophon
while,
if, for, and
foreach
grep,
map, sort, and
print
open, file reading, and
-x (file tests)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";
}current_heading( )) to
a new heading (given as the first parameter to the subroutine).my ($new_heading) = @_;
$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...Current heading is 234. Come about to 234 by turning right 0 degrees.
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";
}current_heading( )) to
a new heading (given as the first parameter to the subroutine).my ($new_heading) = @_;
$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...Current heading is 234. Come about to 234 by turning right 0 degrees.
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";
}turn_towards_heading out into a separate file. For
example, suppose the Skipper figures out a half-dozen common
subroutines related to navigating the Minnow that he seems to use in
most or all of the programs he's writing for the
task. He can put them in a separate file called
navigation.pl, which consists only of the needed
subroutines.sub load_common_subroutines {
open MORE_CODE, "navigation.pl" or die "navigation.pl: $!";
undef $/; # enable slurp mode
my $more_code = <MORE_CODE>;
close MORE_CODE;
eval $more_code;
die $@ if $@;
}navigation.pl is read into the
$more_code variable. You then use
eval to process that text as Perl code. Any
lexical variables in $more_code will remain local
to the evaluated code. If
there's a syntax error, the $@
variable is set and causes the subroutine to die
with the appropriate error message.navigation.pl. If the
Skipper merely inserts:do "navigation.pl"; die $@ if $@;
eval code were executed
earlier.
do operator acts as if the code from
navigation.pl were incorporated into the current
program, although in its own scope block so that lexicals
(my variables) and most directives (such as
use
strict) from the included
file don't leak into the main program.
drop_anchor( ) and places it in the file
drop_anchor.pl.
do "drop_anchor.pl"; die $@ if $@; ... drop_anchor( ) if at_dock( ) or in_port( );
.pl file can have
direct executable statements, it's much more common
to simply define subroutines that can be called by the code
containing the do.drop_anchor.pl library for a
second, imagine what would happen if the Skipper wrote a program that
needed to "drop anchor" as well as
navigate:navigate.pl itself also pulls in
drop_anchor.pl for some common navigation task.
You'll end up reading the file once directly, and
then again while processing the navigation package. This will
needlessly redefine drop_anchor( ). Worse than
that, if warnings are enabled, you'll get a
warning from Perl that you've redefined the
subroutine, even though it's the same definition.require. Change the previous code to simply:require "drop_anchor.pl"; require "navigate.pl";
require operator
keeps track of the files it has read. Once a file has been processed
successfully, any further require operations on
that same file are simply ignored. This means that even if
navigate.pl contains require
"drop_anchor.pl", the
drop_anchor.pl file is brought in exactly once,
and you'll get no annoying error messages about
duplicate subroutine definitions (see Figure 2-2).
Most importantly, you'll also save time by not
processing the file more than once .
require operator also has two additional
features:die, thus the
many die $@ if $@ statements are unnecessary.require have a cryptic 1; as
their last line of code. This ensures that the last evaluated
expression is in fact true. Try to carry on this tradition as well.die
if
... strategy instead, deeming the
"last expression evaluated is
false" strategy a mere historic annoyance.do or require) are
located. That's because it "just
works" for the simplest case, in which you have a
program and its libraries in the same directory, and you run the
program from that directory.PATH environment
variable). The current directory (represented in Unix by a single
dot) is an element of the search path, so as long as your libraries
are in your current working directory, everything is fine.@INC array. By default, the array contains the
current directory and a half-dozen directories built in to the
perl binary during the compilation of
perl itself. You can see what these directories
are by typing perl
-V at the
command line and noting the last dozen lines of the output. Also at
the command line, you can execute the following to get just the
@INC directories:
perl -le 'print for @INC'
@INC, you can alter
@INC itself before the require,
to bring in libraries from one or more directories of your choosing.
The @INC array is an ordinary array, so have the
Skipper add a directory below his home directory to the mix:unshift @INC, "/home/skipper/perl-lib";
navigation.pl and that Gilligan has incorporated
the library into his own navigation package
head_towards_island:#!/usr/bin/perl
require 'navigation.pl';
sub turn_toward_port {
turn_toward_heading(compute_heading_to_island( ));
}
sub compute_heading_to_island {
.. code here ..
}
.. more program here ..navigation.pl library, adding a routine called
turn_toward_port that makes a 45-degree turn
toward the left (known as "port" in
nautical jargon).turn_toward_port from
Gilligan's main program, then when the
require is evaluated at runtime, the definition
for turn_toward_port is redefined as the
Skipper's definition. Sure, if Gilligan has warnings
enabled, he'll notice something is wrong, but why
should he have to count on that?turn_toward_port as meaning "turn
toward the port on the island," while the Skipper
defined it as "turn toward the
left." How do you resolve this?navigation_. Thus, Gilligan's
program ends up looking like:#!/usr/bin/perl
require 'navigation.pl';
sub turn_toward_port {
navigation_turn_toward_heading(compute_heading_to_island( ));
}
sub compute_heading_to_island {
.. code here ..
}
.. more program here ..navigation_turn_toward_heading comes
from the navigation.pl file. This is great for
Gilligan, but awkward for the Skipper, as his file now becomes:sub navigation_turn_toward_heading {
.. code here ..
}
sub navigation_turn_toward_port {
.. code here ..
}
1;package Navigation;
sub turn_towards_heading {
.. code here ..
}
sub turn_towards_port {
.. code here ..
}
1;package declaration at the beginning of this
file tells Perl to insert Navigation:: in front of
most names within the file: Thus, the code above practically says:sub Navigation::turn_towards_heading {
.. code here ..
}
sub Navigation::turn_towards_port {
.. code here ..
}
1;Navigation:: to the subroutines defined in the
library, and leaves the Navigation:: prefix off
for subroutines he defines on his own:#!/usr/bin/perl
require 'navigation.pl';
sub turn_toward_port {
Navigation::turn_toward_heading(compute_heading_to_island( ));
}
sub compute_heading_to_island {
.. code here ..
}
.. more program here ..perlmodlib documentation, a
package name should begin with a capital letter and not overlap an
existing CPAN or core module name. Package names can also consist of
multiple names separated by double colons, such as
Minnow::Navigation and
Minnow::Food::Storage.navigation.pl, you can use variables such as:package Navigation;
@homeport = (21.1, -157.525);
sub turn_toward_port {
.. code ..
}@homeport variable in the
main code as:@destination = @Navigation::homeport;
package
main;. Any
package directive remains in effect until the next
package directive, unless that
package directive is inside a curly-braced scope.
In that case, the prior package is remembered and restored when the
scope ends. Here's an example:package Navigation;
{ # start scope block
package main; # now in package main
sub turn_towards_heading { # main::turn_towards_heading
.. code here ..
}
} # end scope block
# back to package Navigation
sub turn_towards_port { # Navigation::turn_towards_port
.. code here ..
}my variables,
narrowed to the innermost-enclosing brace pair or file in which the
package is introduced.main package. However
it's nice to know that you can temporarily have a
different current package.
my) isn't prefixed by the
current package because package variables are always
global: you can always reference a package
variable if you know its full name. A lexical variable is usually
temporary and accessible for only a portion of the program. If a
lexical variable is declared, then using that name without a package
prefix results in accessing the lexical variable. However, a package
prefix ensures that you are accessing a package variable and never a
lexical variable.navigation.pl declares a lexical
@homeport variable. Any mention of
@homeport will then be the newly introduced
lexical variable, but a fully qualified mention of
@Navigation::homeport accesses the package
variable instead.package Navigation;
@homeport = (21.1, -157.525);
sub get_me_home {
my @homeport;
.. @homeport .. # refers to the lexical variable
.. @Navigation::homeport .. # refers to the package variable
}
.. @homeport .. # refers to the package variable@day = qw(ark dip wap sen pop sep kir);
sub number_to_day_name { my $num = shift @_; $day[$num]; }
@month = qw(diz pod bod rod sip wax lin sen kun fiz nap dep);Today
is
dip, sen
11,
2008, meaning that today is a Monday in August.
(Hint: The year and month numbers returned by
localtime may not be what you'd
expect, so you need to check the documentation.)my($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime;
my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}grep in a scalar
context returns the number of times the expression
$item
eq
$_
returns true, which is 1 if the item is in the list and 0 if
not. If the value is 0, it's false, and you
print the message.my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
for my $item (@required) {
unless (grep $item eq $_, @gilligan) { # not found in list?
print "gilligan is missing $item.\n";
}
}
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
for my $item (@required) {
unless (grep $item eq $_, @professor) { # not found in list?
print "professor is missing $item.\n";
}
}sub check_required_items {
my $who = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
for my $item (@required) {
unless (grep $item eq $_, @_) { # not found in list?
print "$who is missing $item.\n";
}
}
}
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
check_required_items("gilligan", @gilligan);my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}grep in a scalar
context returns the number of times the expression
$item
eq
$_
returns true, which is 1 if the item is in the list and 0 if
not. If the value is 0, it's false, and you
print the message.my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
for my $item (@required) {
unless (grep $item eq $_, @gilligan) { # not found in list?
print "gilligan is missing $item.\n";
}
}
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
for my $item (@required) {
unless (grep $item eq $_, @professor) { # not found in list?
print "professor is missing $item.\n";
}
}sub check_required_items {
my $who = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
for my $item (@required) {
unless (grep $item eq $_, @_) { # not found in list?
print "$who is missing $item.\n";
}
}
}
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
check_required_items("gilligan", @gilligan);@_ array initially: the name
gilligan and the four items belonging to Gilligan.
After the shift, @_ will have
only the items. Thus, the grep checks each
required item against the list.\)
character is also the "take a reference
to" operator. When you use it in front of an array
name, e.g., \@skipper, the result is a
reference to that array. A reference to the
array is like a pointer: it points at the array, but is not the array
itself.my $reference_to_skipper = \@skipper;
my $second_reference_to_skipper = $reference_to_skipper;
my $third_reference_skipper = \@skipper;
if ($reference_to_skipper == $second_reference_to_skipper) {
print "They are identical references.\n";
}@skipper internal data
structure, unchanging during the life of the variable. If you look at
the string form instead, with eq or
print, you get a debugging string:ARRAY(0x1a2b3c)
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
check_required_items("The Skipper", \@skipper);
sub check_required_items {
my $who = shift;
my $items = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
...
}$items@skipper, you'll see that it
consists of two parts: the @ symbol and the name
of the array. Similarly, the syntax $skipper[1]
consists of the name of the array in the middle and some syntax
around the outside to get at the second element of the array (index
value 1 is the second element because you start counting index values
at 0).skipper to name the array, you use the reference
inside curly braces: { $items }. For example, both
of these lines refer to the entire array:@ skipper
@{ $items }$ skipper [1]
${ $items }[1]sub check_required_items {
my $who = shift;
my $items = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
for my $item (@required) {
unless (grep $item eq $_, @{$items}) { # not found in list?
print "$who is missing $item.\n";
}
}
}@_ (the copy of the provisions list) with
@{$items}, a dereferencing of the reference to the
original provisions array. Now you can call the subroutine a few
times as before:my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
check_required_items("The Skipper", \@skipper);
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
check_required_items("Professor", \@professor);
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
check_required_items("Gilligan", \@gilligan);$items points to a different array, so
the same code applies to different arrays each time it is invoked.
This is one of the most important uses of references: decoupling the
code from the data structure on which it operates so the code can be
reused more readily.@{$items} or
${$items}[1]. In those cases, the curly braces can
be dropped, unambiguously, forming @$items or
$$items[1].@{$_[1]} from that last subroutine rewrite, you
can't remove the braces.$$items[1], a pretty noisy piece of
syntax, you can tell that the curly braces must belong around the
simple scalar variable, $items. Therefore,
$items must be a reference to an array.sub check_required_items {
my $who = shift;
my $items = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
for my $item (@required) {
unless (grep $item eq $_, @$items) { # not found in list?
print "$who is missing $item.\n";
}
}
}@$items.sub check_required_items {
my $who = shift;
my $items = shift;
my @required = qw(preserver sunscreen water_bottle jacket);
my @missing = ( );
for my $item (@required) {
unless (grep $item eq $_, @$items) { # not found in list?
print "$who is missing $item.\n";
push @missing, $item;
}
}
if (@missing) {
print "Adding @missing to @$items for $who.\n";
push @$items, @missing;
}
}@missing array. If you
find any items missing during the scan, push them into
@missing. If there's anything
there at the end of the scan, add it to the original provision list.$items array reference, accessing the original
array, and adding the elements from @missing.
Without passing by reference, you'd modify only a
local copy of the data, which has no effect on the original array.@$items (and its more generic form
@{$items}) works within a double-quoted string. Do
not include any whitespace between the @ and the
immediately following character, although you can include nearly
arbitrary whitespace within the curly braces as if it were normal
Perl code.@_ contains two elements, one
of which is also an array. What if you take a reference to an array
that also contains a reference to an array? You end up with a complex
data structure, which can be quite useful.my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
my @skipper_with_name = ("Skipper", \@skipper);
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
my @professor_with_name = ("Professor", \@professor);
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
my @gilligan_with_name = ("Gilligan", \@gilligan);@skipper_with_name has two elements, the second of
which is an array reference, similar to what was passed to the
subroutine. Now group them all:my @all_with_names = ( \@skipper_with_name, \@professor_with_name, \@gilligan_with_name, );
$all_with_names[2] will be the array
reference for the Gilligan's data. If you
dereference it as @{$all_with_names[2]}, you get a
two-element array, "Gilligan" and another array
reference.${$all_with_names[2]}[1]. In
other words, taking $all_with_names[2], you
dereference it in an expression that would be something like
$DUMMY[1] as an ordinary array, so
you'll place {$all_with_names[2]}
in place of DUMMY.check_required_items(
) with this data structure? The following code is easy
enough.for my $person (@all_with_names) {
my $who = $$person[0];
my $provisions_reference = $$person[1];
check_required_items($who, $provisions_reference);
}${$all_with_names[2]}[1]. Now, what if you want to
know Gilligan's first provision? You need to
dereference this item one more level, so
it's Yet Another Layer of Braces:
${${$all_with_names[2]}[1]}[0].
That's a really noisy piece of syntax. Can you
shorten that? Yes!${DUMMY}[$y], you can write
DUMMY->[$y] instead. In other words, you can
dereference an array reference, picking out a particular element of
that array by simply following the expression defining the array
reference with an arrow and a square-bracketed subscript.$all_with_names[2]->[1],
and Gilligan's first provision with
$all_with_names[2]->[1]->[0]. Wow,
that's definitely easier on the eyes.$all_with_names[2]->[1]->[0] becomes
$all_with_names[2][1][0]. Now
it's looking even easier on the eye.@all_with_names:my $root = \@all_with_names;
$root -> [2] -> [1] -> [0]
$root -> [2][1][0]
@root's third element, an
entirely unrelated data structure. Let's compare
this to the full curly-brace form again:${${${$root}[2]}[1]}[0]@{$root->[2][1]}$root.my %gilligan_info = ( name => 'Gilligan', hat => 'White', shirt => 'Red', position => 'First Mate', ); my $hash_ref = \%gilligan_info;
my $name = $ gilligan_info { 'name' };
my $name = $ { $hash_ref } { 'name' };my @keys = keys % gilligan_info;
my @keys = keys % { $hash_ref };my $name = $$hash_ref{'name'};
my @keys = keys %$hash_ref;my $name = $hash_ref->{'name'};my %gilligan_info = ( name => 'Gilligan', hat => 'White', shirt => 'Red', position => 'First Mate', ); my %skipper_info = ( name => 'Skipper', hat => 'Black', shirt => 'Blue', position => 'Captain', ); my @crew = (\%gilligan_info, \%skipper_info);
$crew[0] is a hash reference to the
information about Gilligan. You can get to
Gilligan's name via any one of:${ $crew[0] } { 'name' }
my $ref = $crew[0]; $$ref{'name'}
$crew[0]->{'name'}
$crew[0]{'name'}$ginger->[2][1]
${$ginger[2]}[1]
$ginger->[2]->[1]
${$ginger->[2]}[1]check_required_items, write a subroutine
check_items_for_all that takes a hash reference as
its only parameter, pointing at a hash whose keys are the people
aboard the Minnow, and whose corresponding values are array
references of the things they intend to bring on board.my @gilligan = ... gilligan items ...; my @skipper = ... skipper items ...; my @professor = ... professor items ...; my %all = ( "Gilligan" => \@gilligan, "Skipper" => \@skipper, "Professor" => \@professor, ); check_items_for_all(\%all);
check_required_items for each person in the hash,
updating their provisions list to include the required items.@skipper and place it into a new scalar
variable:my @skipper = qw(blue_shirt hat jacket preserver sunscreen); my $reference_to_skipper = \@skipper;
my $second_reference_to_skipper = $reference_to_skipper; my $third_reference_to_skipper = \@skipper;
@skipper:@skipper @$reference_to_skipper @$second_reference_to_skipper @$third_reference_to_skipper
check_provisions_list(\@skipper)
@_ for the subroutine. The subroutine is free to
create additional copies of that reference, which Perl notes as
needed. Typically, when the subroutine returns, all such references
are discarded automatically, and you're back to four
references again.@skipper and place it into a new scalar
variable:my @skipper = qw(blue_shirt hat jacket preserver sunscreen); my $reference_to_skipper = \@skipper;
my $second_reference_to_skipper = $reference_to_skipper; my $third_reference_to_skipper = \@skipper;
@skipper:@skipper @$reference_to_skipper @$second_reference_to_skipper @$third_reference_to_skipper
check_provisions_list(\@skipper)
@_ for the subroutine. The subroutine is free to
create additional copies of that reference, which Perl notes as
needed. Typically, when the subroutine returns, all such references
are discarded automatically, and you're back to four
references again.@skipper.
For example, you can assign undef to the variable:$reference_to_skipper = undef;
my @skipper = ...;
{
...
my $ref = \@skipper;
...
...
} # $ref goes out of scope at this pointmy $ref;
{
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
$ref = \@skipper;
print "$ref->[2]\n"; # prints jacket\n
}
print "$ref->[2]\n"; # still prints jacket\n@skipper array is declared,
you have one reference to the five-element list. After
$ref is initialized, you'll have
two, down to the end of the block. When the block ends, the
@skipper name disappears. However, this was only
one of the two ways to access the data! Thus, the five-element list
is not removed from memory, and $ref is still
pointing to that data.$ref
is changed, or $ref itself disappears, you can
still continue to use all the dereferencing strategies you used prior
to when the name of the array disappeared. In fact,
it's still a fully functional array that you can
shrink or grow just as you do any other Perl array:push @$ref, "sextant"; # add a new provision print "$ref->[-1]\n"; # prints sextant\n
my $copy_of_ref = $ref;
my $copy_of_ref = \@$ref;
$ref = undef; # not yet... $copy_of_ref = undef; # poof!