Chapter 4. Introduction to References

References are the basis for complex data structures, object-oriented programming, and fancy subroutine handling. They’re the magic that was added between Perl versions 4 and 5 to make it all possible.

A Perl scalar variable holds a single value. An array holds an ordered list of scalars. A hash holds an unordered collection of scalars as values, keyed by strings. Although a scalar can be an arbitrary string, which lets us encode complex data in an array or hash, none of the three data types are well suited to complex data interrelationships. This is a job for the reference. We look at the importance of references by starting with an example.

Doing the Same Task on Many Arrays

Before the Minnow can leave on an excursion (for example, a three-hour tour), we should check every passenger and crew member to ensure they have all the required trip items in their possession. For maritime safety, every person aboard the Minnow needs to have a life preserver, some sunscreen, a water bottle, and a rain jacket. We can write a bit of code to check for the Skipper’s supplies:

my @required = qw(preserver sunscreen water_bottle jacket);
my %skipper  = map { $_, 1 }
  qw(blue_shirt hat jacket preserver sunscreen);

foreach my $item (@required) {
  unless ( $skipper{$item} ) { # not found in list?
    print "Skipper is missing $item.\n";
  }
}

Notice that we created a hash from the list of the Skipper’s items. That’s a common and useful operation. Since we want to check if a particular item is in the Skipper’s list, the easiest way is to make all the items keys of a hash then check the hash with exists. Here, we’ve given every key a true value, so we don’t use exists. Instead of typing out the hash completely, we use the map to create it from the list of items.

If we want to check on Gilligan and the Professor, we might write the following code:

my %gilligan = map { $_, 1 } qw(red_shirt hat lucky_socks water_bottle);
foreach my $item (@required) {
  unless ( $gilligan{$item} ) { # not found in list?
    print "Gilligan is missing $item.\n";
  }
}

my %professor = map { $_, 1 }
  qw(sunscreen water_bottle slide_rule batteries radio);
for my $item (@required) {
  unless ( $professor{$item} ) { # not found in list?
    print "The Professor is missing $item.\n";
  }
}

When we program like this, we start to realize a lot of repeated code here and think that we should refactor that into a common subroutine that we can reuse:

sub check_required_items {
  my $who = shift;
  my %whos_items = map { $_, 1 } @_; # the rest are the person's items

  my @required = qw(preserver sunscreen water_bottle jacket);

  for my $item (@required) {
    unless ( $whos_items{$item} ) { # 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);

Perl gives the subroutine five items in its argument list, the @_ array, initially: the name gilligan and the four items belonging to Gilligan. After the shift, @_ only has the items.

Note

Perl subroutines are covered in perlsub, as well as in Chapter 4 in Learning Perl.

So far, so good. We can check the Skipper and the Professor with a bit more code:

my @skipper   = qw(blue_shirt hat jacket preserver sunscreen);
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
check_required_items('skipper', @skipper);
check_required_items('professor', @professor);

And for the other passengers, we repeat as needed. Although this code meets the initial requirements, we’ve got two problems to deal with:

  • To create @_, Perl copies the entire contents of the array we want to check. This is fine for a few items, but if the array is large, it seems a bit wasteful to copy the data just to pass it into a subroutine.

  • Suppose we want to modify the original array to force the provisions list to include the mandatory items. Because we have a copy in the subroutine (“pass by value”), any changes we make to @_ aren’t reflected automatically in the corresponding provisions array.

Note

Assigning new scalars to elements of @_ after the shift modifies the corresponding variable being passed, but that still wouldn’t let us extend the array with additional mandatory provisions.

To solve either or both of these problems, we need pass by reference rather than pass by value. And that’s just what the doctor (or Professor) ordered.

PeGS: Perl Graphical Structures

Before we get started with references, however, we want to introduce Perl Graphical Structures, or PeGS. These are graphical representations of Perl data structures developed by Joseph Hall. With a pretty picture, some of these illustrate the data layout better than simple text.

Most PeGS diagrams have two parts: the name of the variable and the data it references. The name portion is at the top of the diagram as a box with a pointy right side (see Figure 4-1). The variable name is inside the box.

A partial PeGS diagram showing the identifier portion

Figure 4-1. A partial PeGS diagram showing the identifier portion

For a scalar, we have a single box under the name to hold its single value (see Figure 4-2).

The PeGS diagram for a scalar

Figure 4-2. The PeGS diagram for a scalar

For an array (Figure 4-3), which can have multiple values, we do a bit more. The data portion starts with a filled-in, solid bar at the top to denote that it is a collection (to distinguish the single element array from a scalar).

The PeGS diagram for an array

Figure 4-3. The PeGS diagram for an array

The hash is even more fancy. Like the array, the data portion starts with a black bar, but under that it has two parts. On the left are the keys, in pointy-sided boxes pointing at the box on their right, which shows the corresponding value (see Figure 4-4).

The PeGS diagram for a hash

Figure 4-4. The PeGS diagram for a hash

We’ll draw some of our complex data structures using these diagrams, and as we go further along we’ll introduce some other features of PeGS.

Taking a Reference to an Array

Among its many other meanings, the backslash (\) character is also the “take a reference to” operator. When we use it in front of an array name, for example, \@skipper, the result is a reference to that array. A reference to the array is like a pointer:[7] it points at the array, but is not the array itself. (See Figure 4-5.)

A reference fits wherever a scalar fits. It can go into an element of an array or a hash, or into a plain scalar variable, like this:

my $ref_to_skipper = \@skipper;
The PeGS diagram for a reference

Figure 4-5. The PeGS diagram for a reference

In the PeGS notation, the reference is just a scalar, so its diagram looks like a scalar. However, in the data portion, it points to the data it references. Notice that the arrow from the reference to the data points specifically to the data, not the name of the variable that also references the data. That’s going to be important very soon.

We can copy the reference to another reference, and both references point to the same data (see Figure 4-6):

my $second_ref_to_skipper = $reference_to_skipper;
@skipper with one other reference pointing to the same data

Figure 4-6. @skipper with one other reference pointing to the same data

We can even do it again (see Figure 4-7):

my $third_ref_to_skipper = \@skipper;
@skipper with two other references pointing to the same data

Figure 4-7. @skipper with two other references pointing to the same data

We can interchange all three references. We can even say they’re identical, because they are the same thing. When we compare reference with ==, we get back true if they point to the same data address:

if ($reference_to_skipper == $second_reference_to_skipper) {
  print "They are identical references.\n";
}

This equality compares the numeric forms of the two references. The numeric form of the reference is the unique memory address of the @skipper internal data structure, which is unchanging during the life of the data. If we look at the string form instead, with eq or print, we get a string form of the reference:

ARRAY(0x1a2b3c)

This string is unique for this array because it includes the hexadecimal (base 16) representation of the array’s memory address. The debugging string also notes that this is an array reference. If we ever see something like this in our output, it almost certainly means we have a bug; users of our program have little interest in hex dumps of storage addresses!

Also, the references need to point to the same data in Perl’s memory, not two different data that just happen to have the same values.

Because we can copy a reference, and passing an argument to a subroutine is really just aliasing, we can use this code to pass a reference to the array into the subroutine:

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);
  ...
}

Now $items in the subroutine is a reference to the array of @skipper. But how do we get from a reference back into the original array? We dereference the reference.

Dereferencing the Array Reference

If we look at @skipper, we’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 index values start at 0).

Here’s the trick: we can place any reference to an array in curly braces in place of the name of an array, ending up with a method to access the original array. That is, wherever we write skipper to name the array, we use the reference inside curly braces: { $items }. For example, both of these lines refer to the entire array:

@  skipper
@{ $items }

whereas both of these refer to the second item of the array:[8]

$  skipper [1]
${ $items }[1]

By using the reference form, we’ve decoupled the code and the method of array access from the actual array. We see how that changes the rest of this subroutine:

sub check_required_items {
  my $who   = shift;
  my $items = shift;

  my %whos_items = map { $_, 1 } @{$items};

  my @required = qw(preserver sunscreen water_bottle jacket);
  for my $item (@required) {
    unless ( $whos_items{$item} ) { # not found in list?
      print "$who is missing $item.\n";
    }
  }
}

All we did was replace @_ (the copy of the provisions list) with @{$items}, a dereferencing of the reference to the original provisions array. Now we 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);

In each case, $items points to a different array, so the same code applies to different arrays each time we invoke it. This is one of the most important uses of references: decoupling the code from the data structure on which it operates so we can reuse the code more readily.

Passing the array by reference fixes the first of the two problems we mentioned earlier. Now, instead of copying the entire provision list into the @_ array, we get a single element, which is a reference to that provisions array.

Could we have eliminated the two shifts at the beginning of the subroutine? Sure, but we sacrifice clarity:

sub check_required_items {
  my %whos_items = map {$_, 1} @{$_[1]};

  my @required = qw(preserver sunscreen water_bottle jacket);
  for my $item (@required) {
    unless ( $whos_items{$item} ) { # not found in list?
      print "$_[0] is missing $item.\n";
    }
  }
}

We still have two elements in @_. The first element is the passenger or crew member name, which we use in the error message. The second element is a reference to the correct provisions array, which we use in the grep expression.

Getting Our Braces Off

Most of the time, the array reference we want to dereference is a simple scalar variable, such as @{$items} or ${$items}[1]. In those cases, we can drop the curly braces, unambiguously forming @$items or $$items[1].

However, we cannot drop the braces if the value within the braces is not a bareword identifier with one or more leading $s. For example, for @{$_[1]} from that last subroutine rewrite, we can’t remove the braces. That’s a single element access to an array, not a scalar variable, so it has more than the identifier and $s. We could drop the braces from @{$items} and @{$$items} though.

This rule also means that it’s easy to see where the “missing” braces need to go. When we see $$items[1], a pretty noisy piece of syntax, we can tell that the curly braces must belong around the simple scalar variable, $items. Therefore, $items must be a reference to an array.

Thus, an easier-on-the-eyes version of that subroutine might be:

sub check_required_items {
  my( $who, $items ) = @_;
  my %whos_items = map {$_, 1} @$items;

  my @required = qw(preserver sunscreen water_bottle jacket);
  for my $item (@required) {
    unless ( $whos_items{$item} ) { # not found in list?
      print "$who is missing $item.\n";
    }
  }
}

The difference here is that we removed the braces around @$items.

Modifying the Array

We solved the excessive copying problem with an array reference. Now we modify the original array.

For every missing provision, we push that provision onto an array, forcing the passenger to consider the item:

sub check_required_items {
  my $who   = shift;
  my $items = shift;

  my %whose_items = map { $_, 1 } @$items;

  my @required = qw(preserver sunscreen water_bottle jacket);
  my @missing = (  );

  for my $item (@required) {
    unless ( $whose_items{$item} ) { # 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;
  }
}

Note the addition of the @missing array. If we find any items missing during the scan, we push them into @missing. If there’s anything there at the end of the scan, we add it to the original provision list.

The key is in the last line of that subroutine. We’re dereferencing the $items array reference, accessing the original array, and adding the elements from @missing. Without passing by reference, we’d modify only a local copy of the data, which has no effect on the original array.

Also, @$items (and its more generic form @{$items}) works within a double-quoted string and interpolates like a normal, named array. We can’t include any whitespace between the @ and the character immediately following, although we can include arbitrary whitespace within the curly braces as if it were normal Perl code.

Nested Data Structures

In this next example, the array @_ contains two elements, one of which is an array reference. What if we take a reference to an array that also contains a reference to an array? We end up with a complex data structure, which can be quite useful.

For example, we can iterate over the data for the Skipper, Gilligan, and the Professor by first building a larger data structure holding the entire list of provision lists:

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);

At this point, @skipper_with_name has two elements, the second of which is an array reference similar to what we passed to the subroutine. Now we group them all:

my @all_with_names = (
  \@skipper_with_name,
  \@professor_with_name,
  \@gilligan_with_name,
);

We have three elements in @all_with_names, each of which is a reference to an array with two elements: the name and its corresponding initial provisions. A picture of that is in Figure 4-8.

The array @all_with_names holds a multilevel data structure containing strings and references to arrays

Figure 4-8. The array @all_with_names holds a multilevel data structure containing strings and references to arrays

Therefore, $all_with_names[2] is the array reference for the Gilligan’s data. If we dereference it as @{$all_with_names[2]}, we get a two-element array, “Gilligan,” and another array reference.

How do we access that array reference? Using our rules again, it’s ${$all_with_names[2]}[1]. In other words, taking $all_with_names[2], we dereference it in an expression that would be something like $DUMMY[1] as an ordinary array, so we’ll place {$all_with_names[2]} in place of DUMMY.

How do we call the existing 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);
}

This requires no changes to our subroutine. The control variable $person goes through each of $all_with_names[0], $all_with_names[1], and $all_with_names[2], as the loop progresses. When we dereference $$person[0], we get “Skipper,” “Professor,” and “Gilligan,” respectively. $$person[1] is the corresponding array reference of provisions for that person.

We can shorten this as well since the entire dereferenced array matches the argument list precisely:

for my $person (@all_with_names) {
  check_required_items(@$person);
}

or even:

check_required_items(@$_) for @all_with_names;

Various levels of optimization can lead to obfuscation. We should consider where our heads will be a month from now when we have to reread our own code. If that’s not enough, we should consider the new person who takes over our job after we have left.[9]

Simplifying Nested Element References with Arrows

Look at the curly-brace dereferencing again. As in our earlier example, the array reference for Gilligan’s provision list is ${$all_with_names[2]}[1]. Now, what if we want to know Gilligan’s first provision? We 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 we shorten that? Yes!

Everywhere we write ${DUMMY}[$y], we can write DUMMY−>[$y] instead. In other words, we can dereference an array reference, picking out a particular element of that array by following the expression defining the array reference with an arrow and a square-bracketed subscript.

For this example, this means we can pick out the array reference for Gilligan with a simple $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.

If that wasn’t already simple enough, there’s one more rule: if the arrow ends up between “subscripty kinds of things,” such as square brackets, we can also drop the arrow because multiple subscripts imply a dereference already. $all_with_names[2]−>[1]−>[0] becomes $all_with_names[2][1][0]. Now it’s looking even easier on the eyes.

The arrow has to be between nonsubscripty things. Why wouldn’t it be between subscripty things? Well, imagine a reference to the array @all_with_names:

my $root = \@all_with_names;

Now how do we get to Gilligan’s first item? We line up the subscripts:

$root > [2] > [1] > [0]

More simply, using the “drop arrow” rule, we can use:

$root > [2][1][0]

We cannot drop the first arrow, however, because that would mean an array @root’s third element, an entirely unrelated data structure. We compare this to the full curly-brace form again:

${${${$root}[2]}[1]}[0]

It looks much better with the arrow. Note, however, that no shortcut gets the entire array from an array reference. If we want all of Gilligan’s provisions, we say:

@{$root>[2][1]}

Reading this from the inside out, we can think of it like this:

  1. Take $root.

  2. Dereference it as an array reference, taking the third element of that array (index number 2): $root−>[2]

  3. Dereference that as an array reference, taking the second element of that array (index number 1): $root−>[2][1]

  4. Dereference that as an array reference, taking the entire array: @{$root−>[2][1]}

The last step doesn’t have a shortcut arrow form. Oh well.

References to Hashes

Just as we can take a reference to an array, we can also take a reference to a hash. Once again, we use the backslash as the “take a reference to” operator and store the result in a scalar (see Figure 4-9):

my %gilligan_info = (
  name     => 'Gilligan',
  hat      => 'White',
  shirt    => 'Red',
  position => 'First Mate',
);
my $hash_ref = \%gilligan_info;
The PeGS for the %gilligan_info hash

Figure 4-9. The PeGS for the %gilligan_info hash

We can dereference a hash reference to get back to the original data. The strategy is the same as dereferencing an array reference. We write the hash syntax as we would have without references and then replace the name of the hash with a pair of curly braces surrounding the thing holding the reference. For example, to pick a particular value for a given key, we do this:

my $name = $ gilligan_info { 'name' };
my $name = $ { $hash_ref } { 'name' };

Here, the curly braces have two different meanings. The first pair denotes the expression returning a reference while the second pair delimits the expression for the hash key.

To apply an operation on the entire hash, we proceed similarly:

my @keys = keys % gilligan_info;
my @keys = keys % { $hash_ref };

As with array references, we can use shortcuts to replace the complex curly-braced forms under some circumstances. For example, if the only thing inside the curly braces is a simple scalar variable (as shown in these examples so far), we can drop the curly braces:

my $name = $$hash_ref{'name'};
my @keys = keys %$hash_ref;

Like an array reference, when referring to a specific hash element, we can use an arrow form (see Figure 4-10):

my $name = $hash_ref>{'name'};

Because a hash reference fits wherever a scalar fits, we can create an array of hash references:

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);

Thus, $crew[0] is a hash reference to the information about Gilligan. We 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'}
Crew roster PeGS

Figure 4-10. Crew roster PeGS

With those last two, we can still drop the arrow between “subscripty kinds of things,” even though one is an array bracket and one is a hash brace.

We print a crew roster:

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);

my $format = "%−15s %−7s %−7s %−15s\n";
printf $format, qw(Name Shirt Hat Position);
foreach my $crewmember (@crew) {
  printf $format,
    $crewmember>{'name'},
    $crewmember>{'shirt'},
    $crewmember>{'hat'},
    $crewmember>{'position'};
}

That last part looks repetitive. We can shorten it with a hash slice. Again, if the original syntax is:

@ gilligan_info { qw(name position) }

the hash slice notation from a reference looks like:

@ { $hash_ref } { qw(name position) }

Note

For a review of hash slices, see Learning Perl, Chapter 17. These are also documented in perldata.

We can drop the first brace pair because the only thing within is a simple scalar value, yielding:

@ $hash_ref { qw(name position) }

Thus, we can replace that final loop with:

for my $crewmember (@crew) {
  printf $format, @$crewmember{qw(name shirt hat position)};
}

There is no shortcut form with an arrow (−>) for array slices or hash slices.

A hash reference prints as a string that looks like HASH(0x1a2b3c), showing the hexadecimal memory address of the hash. That’s not useful to an end user and only barely more usable to the programmer, except as an indication of the lack of appropriate dereferencing.

Checking Reference Types

Once we start using references and passing them around, we have to ensure that we know which sort of reference we have. If we try to use the reference as a type that it is not, our program will blow up:

show_hash( \@array );

sub show_hash {
  my $hash_ref = shift;

  foreach my $key ( keys %$hash_ref ) {
    ...
  }
}

The show_hash subroutine expects a hash and trusts that we pass it one. However, since we passed it an array reference, our program blows up:

Not a HASH reference at line ...

If we want to be careful, we should check the argument to show_hash to ensure that it’s actually a hash reference. There are a couple ways that we could do this. The easy way uses ref, which returns the reference type. We compare the return value from ref to what we expected:

use Carp qw(croak);

sub show_hash {
  my $hash_ref = shift;
  my $ref_type = ref $hash_ref;
  croak "I expected a hash reference!"
    unless $ref_type eq 'HASH';

  foreach my $key ( keys %$hash_ref ) {
    ...
  }
}

That looks odd to us, though, because we had to hardcode the literal string HASH. We never like to do that. We can, however, get rid of the literal string with a double use of ref. We call ref a second time with a trivial version of the reference type that we expect:

croak "I expected a hash reference!"
  unless $ref_type eq ref {};

Alternatively, we can use the constant module to store the hash reference string:

use constant HASH => ref {};

croak "I expected a hash reference!"
  unless $ref_type eq HASH;

Using a constant looks a lot like a literal string, but it has an important difference: the constant will fail if we use the wrong name because it is not defined, but a wrong literal string will never fail because Perl has no way to know that we used the wrong string.

Our use of ref has another problem, which we can’t fully explain until we talk about objects. Since ref returns a string that gives the reference type, if we have an object that can act like a hash reference, our technique fails because the strings won’t be the same. The Scalar::Util module, which comes with Perl, gets around that with its reftype function that does the same thing:

use Carp qw(croak);
use Scalar::Util qw(reftype);

sub show_hash {
  my $hash_ref = shift;
  my $ref_type = reftype $hash_ref;  # works with objects
  croak "I expected a hash reference!"
    unless $ref_type eq ref {};

  foreach my $key ( keys %$hash_ref ) {
    ...
  }
}

However, objects are interfaces, so things that are not based on hash references can still act like hashes. In that case, ref doesn’t return the string HASH necessarily.

Instead of asking “What are you?” we should ask “What can you do?” We really only want to know if the argument to show_hash can act like a hash reference so it doesn’t blow up. We don’t specifically care that it is exactly a hash reference.

In that case, we might use an eval in which we try to do something hash-like. If the eval fails and returns false, we didn’t have a hash:

croak "I expected a hash reference!"
  unless eval { keys %$hash_ref; 1 };

If we expect to check this often, we should probably wrap the check in its own subroutine:

sub is_hash_ref {
  my $hash_ref = shift;

  return eval { keys %$ref_type; 1 };
}

croak "I expected a hash reference!"
  unless is_hash_ref( $ref_type );

Exercises

You can find the answers to these exercises in Answers for Chapter 4.

  1. [5 minutes] How many different things do these expressions refer to? Draw a PeGS structure for each of these:

    $ginger>[2][1]
    ${$ginger[2]}[1]
    $ginger>[2]>[1]
    ${$ginger>[2]}[1]
  2. [30 minutes] Using the final version of check_required_items, write a subroutine check_items_for_all that takes as its only parameter a reference to 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.

    For example, the hash reference might be constructed like so:

    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);

    The newly constructed subroutine should call check_required_items for each person in the hash, updating their provisions list to include the required items.

    Some starting code is in the Downloads section on http://www.intermediateperl.com/.

  3. [20 minutes] Modify the crew roster program to add a location field for each castaway. At the start, set each person’s location to “The Island.” After you’ve added that field to each person’s hash, change the Howells’ locations to “The Island Country Club.” Make a report of everyone’s location, like this:

    Gilligan at The Island
    Skipper at The Island
    Mr. Howell at The Island Country Club
    Mrs. Howell at The Island Country Club

    Some starting code is in the Downloads section on http://www.intermediateperl.com/.



[7] We’re not talking about pointers in the C sense, but in the dog sense. Think of an English pointer showing where the duck is, not a memory address.

[8] We added whitespace in these two displays to make the similar parts line up. This whitespace is legal in a program, even though most programs won’t use it.

[9] O’Reilly Media, Inc., has a great book to help us be nice to the next guy. Perl Best Practices, by Damian Conway, has 256 tips on writing more readable and maintainable Perl code.

Get Intermediate Perl, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.