References: names for bigger data
A reference is one value that points at a list or a hash, which is how a record is built in Perl — and how a list of records is built from it.
A value that points at something
A list inside a list is not a list of lists: Perl flattens them into one long list. The way round that is a reference, made with a backslash. my $ref = \@scores; is a single value that knows where the array is.
The names look alike and mean different things. @scores is the whole list, $scores[0] is one item of it, and $ref is a single value pointing at the list. Printing a reference shows something like ARRAY(0x...), which is the interpreter telling you it is not a piece of text.
Using what a reference points at
An arrow reads through the reference: $ref->[0] is the first item of the array it points at, and $ref->{'name'} is an entry of the hash it points at. A sigil in front reads the whole thing at once: @$ref is the list itself and %$ref is the hash itself.
The important part is that this is the same data, not a copy. push @$ref, 88; adds to @scores, and setting $who->{'age'} changes %person. A reference is a second name for what you already had, which is why it is the right tool for anything bigger than one value.
Records
A hash holding one thing — a person, a book, a machine in a rack — is a record, and records live in a list: my @rows = ({ 'name' => 'Ada' }, { 'name' => 'Grace' });. The braces make each item a hash reference, and $row->{'name'} reads one field of one row.
This shape, an array of hash references, is what Perl data looks like. Everything in the next chapter works on it: grep over the rows to keep some, a comparator block to sort them by a field, and a loop with printf to print them as a table.
What a reference actually holds
A reference is a scalar whose value describes another piece of data: the kind of thing it points at and where that thing lives. Printing one shows something like ARRAY(0x...) because a reference is not text; it is a handle. ref($r) asks the kind, and answers ARRAY or HASH or the class name of an object.
A backslash takes a reference to something that already has a name: \@scores, \%person. Square brackets and braces make an unnamed one directly: [1, 2, 3] is an array reference and { 'name' => 'Ada' } is a hash reference. Those two forms are how a record is written inline.
Dereferencing is reading through the handle
The sigil in front reads the whole thing: @$list is the array, %$hash is the hash. The arrow reads one piece: $list->[0] is the first item and $hash->{'name'} is one field. The arrow is usually clearer than a doubled sigil, and it chains naturally through nested structures.
Because a reference is a value, it can sit in a list without being flattened. That is the whole trick behind a list of records: each row is one hash reference, so the outer array holds rows rather than a long run of unrelated fields. A reference is also shared, so passing one into a subroutine lets the subroutine change the original.
A reference is how a subroutine shares data
A subroutine receives a flat list, so passing a hash gives it the pairs rather than the hash. Passing \%person instead gives it one value, and my ($person) = @_; names it; $person->{'name'} then reads a field of the caller's own data, and a write through that arrow changes the caller's hash.
That is the trade references make: a subroutine can work on a large structure without copying it, and the price is that the caller and the subroutine now share it.
An array reference, a hash reference, and three rows
use strict;
use warnings;
my @scores = (72, 95, 60);
my $list = \@scores;
push @$list, 88; # @scores changes too
print "list: ", join(' ', @$list), "\n";
print "first: ", $list->[0], "\n";
print "count: ", scalar @scores, "\n";
my %person = ('name' => 'Ada', 'age' => 36);
my $who = \%person;
$who->{'age'} = 37;
print "age: ", $person{'age'}, "\n";
print "keys: ", join(', ', sort keys %$who), "\n";
my @rows = (
{ 'name' => 'Ada', 'score' => 95 },
{ 'name' => 'Grace', 'score' => 72 },
);
foreach my $row (@rows) {
print $row->{'name'}, " scored ", $row->{'score'}, "\n";
}Two references, and a list of records
Run it and check that the push and the age change are visible through both names. Then add a third row to the list and print its fields in the same loop.
A reference is a second name for the same data, so copying one is not copying the data: an ordinary assignment gives you two names for one list. When you want a duplicate, build it again — my @copy = @$list; for an array, or a new hash holding the same pairs.
Three reference mistakes are easy to make. $ref[0] reads an array called @ref, not the list the reference points at; the arrow is $ref->[0]. %$ref and $ref->{'key'} are not interchangeable: one is the whole hash, the other is one value. And printing a reference gives an address-like string, so print what it points at instead.
Try these next
- Build a hash of arrays for two teams, then print each team and its member count.
- Copy a reference into a second variable, change the data through the copy, and print the original to show they share it.
- Use
refto print the kind of an array reference and a hash reference.
A roster of teams
Run it and check that each team prints its own members. Then add a third team and one more member to an existing team, and print the total count.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Why is each row of a list of records a hash reference?
