Perl Part I · Module 7 · References
Dereferencing
A reference is useless until you open it. Dereferencing is that step, and Perl gives you more than one spelling for it: a braced form that always works, a bare form that works only sometimes, and an arrow that Chapter 7.4 is devoted to. Learning all three is worth it because you will read all three in other people's code. The part that actually causes bugs is not the spelling, though — it is the sigil you put in front. The sigil decides whether you are asking for the whole container, one element, or a slice, and one of the plausible-looking combinations quietly gives you a slice when you wanted an element.
Intermediate16 min readPerlPart IReferencesData Structures
Part I · Module 7 · Chapter 7.3 · Dereferencing
1. The Whole Container
Put the sigil of the thing you want in front of the reference.
use strict;
use warnings;
my @marks = (72, 65, 90);
my %conf = (retries => 3, timeout => 45);
my $aref = \@marks;
my $href = \%conf;
print "whole array, braced : @{ $aref }\n";
print "whole array, bare : @$aref\n";
printf "element count : %d\n", scalar(@$aref);
printf "last index, braced : %d\n", $#{ $aref };
printf "last index, bare : %d\n", $#$aref;
printf "first element, braced : %d\n", ${ $aref }[0];
printf "first element, bare : %d\n", $$aref[0];
printf "first element, arrow : %d\n", $aref->[0];
printf "one hash value : %d\n", ${ $href }{retries};
printf "same, arrow : %d\n", $href->{retries};
printf "key count : %d\n", scalar(keys %$href);whole array, braced : 72 65 90
whole array, bare : 72 65 90
element count : 3
last index, braced : 2
last index, bare : 2
first element, braced : 72
first element, bare : 72
first element, arrow : 72
one hash value : 3
same, arrow : 3
key count : 2@{ $aref } means "the array that $aref refers to", and from there everything behaves like an ordinary array. %{ $href } does the same for a hash, which is why keys %$href works.
Note the last line prints the key count, not the keys. Chapter 6.5 established that keys returns an unpredictable order, and that does not change just because you reached the hash through a reference.
| You want | Write |
|---|---|
| the whole array | @{ $aref } or @$aref |
| its element count | scalar(@{ $aref }) or scalar(@$aref) |
| its last index | $#{ $aref } or $#$aref |
| the whole hash | %{ $href } or %$href |
| its keys | keys %{ $href } or keys %$href |
| one array element | ${ $aref }[0] or $$aref[0] or $aref->[0] |
| one hash value | ${ $href }{k} or $$href{k} or $href->{k} |
2. Everything Ordinary Still Works
Once dereferenced, it is just an array. Every builtin from Modules 5 and 6 applies.
use strict;
use warnings;
my @data = (3, 1, 2);
my $r = \@data;
push @$r, 4;
print "after push : @$r\n";
print "sorted : ", join(" ", sort { $a <=> $b } @$r), "\n";
print "grep > 2 : ", join(" ", grep { $_ > 2 } @$r), "\n";
printf "count : %d\n", scalar(@$r);
printf "last index : %d\n", $#$r;after push : 3 1 2 4
sorted : 1 2 3 4
grep > 2 : 3 4
count : 4
last index : 3push, sort, grep, scalar, $# — none of them know or care that you arrived through a reference. And push @$r, 4 modified @data, for Chapter 7.2 §2's reason: there is one array.
3. The Three Element Forms Are One Thing
use strict;
use warnings;
my @data = (10, 20, 30);
my $r = \@data;
printf "braced \${\$r}[1] : %d\n", ${$r}[1];
printf "bare \$\$r[1] : %d\n", $$r[1];
printf "arrow \$r->[1] : %d\n", $r->[1];braced ${$r}[1] : 20
bare $$r[1] : 20
arrow $r->[1] : 20Identical. Pick one and be consistent; the arrow is the one to pick, and Chapter 7.4 explains why it wins once structures nest. The other two matter because you will read them.
Which way does $$r[0] group?
This is worth one measurement because guessing wrong is a real source of confusion.
use strict;
use warnings;
my @data = (10, 20);
my $r = \@data;
printf "%d\n", $$r[0];10use strict;
use warnings;
my @data = (10, 20);
my $r = \@data;
printf "%d\n", ${$r[0]};Global symbol "@r" requires explicit package name (did you forget to declare "my @r"?) at group-bad.pl line 7.
Execution of group-bad.pl aborted due to compilation errors.$$r[0] means ${$r}[0]. The second reading is not merely different, it refers to a different variable — ${$r[0]} subscripts @r, an array that does not exist, so it will not even compile.
The rule: the subscript applies last. The leading sigils resolve the reference first, then [0] indexes the result.
4. The Sigil Decides — Element, Slice, or Count
This is the section that prevents bugs.
use strict;
use warnings;
my @data = (10, 20, 30);
my $r = \@data;
my $whole = @$r;
my $element = $$r[0];
printf "my \$x = \@\$r : %d <- the COUNT\n", $whole;
printf "my \$y = \$\$r[0] : %d <- the element\n", $element;
my @slice = @$r[0, 1];
printf "\@\$r[0,1] : %d item(s) [%s]\n", scalar(@slice), join(" ", @slice);my $x = @$r : 3 <- the COUNT
my $y = $$r[0] : 10 <- the element
@$r[0,1] : 2 item(s) [10 20]Three different results from three sigil choices on the same reference:
@$r— the whole array. In scalar context that is its count, exactly as Chapter 5.7 described.$$r[0]— one element.@$r[0,1]— a slice, which is a list.
5. Slices Through a Reference
When you genuinely do want a list, slices work exactly as Chapter 5.3 and Chapter 6.7 describe.
use strict;
use warnings;
my @data = (10, 20, 30);
my %h = (a => 1, b => 2, c => 3);
my $r = \@data;
my $hr = \%h;
print "array slice, braced : @{ $r }[1,2]\n";
print "array slice, bare : @$r[1,2]\n";
print "hash slice, braced : @{ $hr }{ qw(a c) }\n";
print "hash slice, bare : @$hr{ qw(a c) }\n";array slice, braced : 20 30
array slice, bare : 20 30
hash slice, braced : 1 3
hash slice, bare : 1 3A hash slice through a reference is genuinely useful: @$href{qw(name width)} pulls two named fields out of a record in one expression.
6. Why the Braced Form Exists
The bare form has a real limitation, and it is not a style question.
use strict;
use warnings;
my %r = (blocks => ["alu", "fifo"]);
print "braced : @{ $r{blocks} }\n";braced : alu fifoNow the same thing without braces:
use strict;
use warnings;
my %r = (blocks => ["alu", "fifo"]);
print "bare : @$r{blocks}\n";Global symbol "$r" requires explicit package name (did you forget to declare "my $r"?) at braces-omitted.pl line 6.
Execution of braces-omitted.pl aborted due to compilation errors.Read that error carefully: it is complaining about $r, a scalar that was never declared. @$r{blocks} did not parse as "dereference $r{blocks}" at all — it parsed as a hash slice of the hash referred to by a scalar $r. Completely different code.
The bare form only works when the reference sits in a simple scalar variable. Anything more complicated — a hash element, an array element, a function's return value — needs braces:
@{ $r{blocks} } # ref from a hash element
@{ $rows[3] } # ref from an array element
@{ get_list() } # ref from a function call
@{ $self->{items} } # ref from a nested lookupuse strict;
use warnings;
sub get_list { return [1, 2, 3] }
printf "count: %d\n", scalar(@{ get_list() });count: 3That is why experienced Perl tends toward braces even in the simple case: one habit that always works beats two habits with a boundary between them. In practice most code uses the arrow for elements and braces for whole containers, which is the combination Chapter 7.4 settles on.
7. Dereferencing the Wrong Kind of Thing
Every one of these is fatal and exits 255. Nothing here warns-and-continues.
keys %$aref -> Not a HASH reference at -e line 1.
@$href -> Not an ARRAY reference at -e line 1.
@$code_ref -> Not an ARRAY reference at -e line 1.
$$aref -> Not a SCALAR reference at -e line 1.my $s = "hello"; @$s -> Can't use string ("hello") as an ARRAY ref while "strict refs" in use at -e line 1.
my $r; @$r -> Can't use an undefined value as an ARRAY reference at -e line 1.There are two message families, and the difference tells you what went wrong:
Not a HASH reference/Not an ARRAY reference— you had a real reference, of the wrong kind. Usually a structure that is not shaped the way you assumed: you wrote$h->{list}{name}wherelistholds an array reference.Can't use ...— you did not have a reference.Can't use an undefined valuemeans the thing wasundef, which usually means a lookup missed;Can't use string ("hello")means a plain value arrived where a reference was expected.
8. Dereferencing Inside Strings
All the forms interpolate, which is worth knowing because it keeps report code readable.
use strict;
use warnings;
my @data = (10, 20);
my %h = (a => 1);
my $r = \@data;
my $hr = \%h;
print "bare array : @$r\n";
print "braced array : @{ $r }\n";
print "element bare : $$r[0]\n";
print "element arrow: $r->[0]\n";
print "hash arrow : $hr->{a}\n";
print "hash braced : ${ $hr }{a}\n";bare array : 10 20
braced array : 10 20
element bare : 10
element arrow: 10
hash arrow : 1
hash braced : 1The array forms join with a space, following Chapter 4.2's rule for array interpolation. The arrow works inside strings too, which is not true in every language with arrow syntax and is genuinely convenient.
9. Why This Matters in Engineering Work
Reading a nested structure is dereferencing, repeatedly. $report->{blocks}{alu}{slack} is three dereferences. Everything in Chapters 7.6 through 7.10 is this chapter applied several times in a row.
The two error families are a fast diagnostic. When a script dies on a netlist or report that is shaped slightly differently from the one you developed against, the message tells you which half of the problem you have: Not an ARRAY reference means your assumption about the structure's shape was wrong, Can't use an undefined value means a lookup returned nothing. Those lead to different fixes, and distinguishing them without a debugger is worth the thirty seconds it takes to learn the wording.
And the sigil discipline is what keeps the code honest. In a loop over ten thousand timing paths, @$r[0] instead of $$r[0] will not announce itself. Leading with $ for one value and @ for a list — or just using the arrow — removes the whole class.
10. Common Mistakes
@$r[0] when you meant $$r[0]. That is a one-element slice. It returns the right value and does not warn, so it survives until the shape matters.
my $n = @$r expecting an element. That is the count.
Omitting braces when the reference is not a simple scalar. @$r{blocks} is a hash slice, and the error names a variable you never wrote.
Reading ${$r[0]} as $$r[0]. Different variable; it needs @r.
Hash-dereferencing an array reference. Not a HASH reference, fatal.
Chasing a Can't use an undefined value into the dereference. Look at the key on the line before.
Assuming keys %$href has an order. It does not, through a reference or otherwise.
11. Exercise
Exercise 1 — the whole container. Take references to a three-element array and a two-key hash. Print the whole array both braced and bare, its count, its last index, and the hash's key count. Do not print the keys themselves, and say in one sentence why not.
Exercise 2 — builtins through a reference. Through an array reference only, push a value, print the array sorted numerically, and print the elements greater than 2. Then confirm the original named array changed.
Exercise 3 — three spellings. Print element 1 using the braced, bare and arrow forms. Confirm all three agree, then state which you intend to use for the rest of the module.
Exercise 4 — the grouping proof. Print $$r[0] successfully. Then write ${$r[0]} and record the compile error. Explain in one sentence which variable the second form was looking for.
Exercise 5 — the sigil trap. On a three-element array reference, print my $x = @$r, $$r[0], and the length of my @y = @$r[0]. Then do the same with @$r[0,1]. Say which of these you would never write deliberately.
Exercise 6 — braces required. Build my %r = (blocks => ["alu","fifo"]);. Print the inner list with braces. Then try it without braces, record the exact error, and explain why the error names $r.
Exercise 7 — both error families. Produce all four of: Not a HASH reference, Not an ARRAY reference, Can't use an undefined value as an ARRAY reference, and Can't use string (...) as an ARRAY ref. Record each message and exit status, then write one sentence per family saying what it tells you to go and look at.
Exercise 8 — the key typo that says nothing. Build a hash reference with a key blocks holding a two-element array reference, then loop over @{ $conf->{block} } — singular. Record STDOUT, STDERR and the exit status. Then check whether block exists in the hash afterwards. Finally, put the same misspelled lookup in my @x = @{ $conf->{block} }; and record what changes. Write one sentence on which of the two you would rather ship.
12. Summary
- Put the sigil of what you want in front of the reference:
@$aref,%$href,$#$aref,keys %$href. - Once dereferenced it is an ordinary container —
push,sort,grep,scalarall work unchanged, and they modify the original. ${$r}[1],$$r[1]and$r->[1]are the same element. The arrow is the one to adopt.$$r[0]means${$r}[0]— the subscript applies last.${$r[0]}is a different variable.- The sigil decides the shape:
@$ris the whole array (a count in scalar context),$$r[0]is an element, and@$r[0]is a one-element slice that never warns. - The bare form only works when the reference is in a simple scalar. A hash element, array element or function result needs
@{ ... }. - Wrong-kind dereference is fatal, and there are two families:
Not a HASH referencewhen it is a reference of the wrong kind,Can't use ...when it is not a reference at all. Can't use an undefined valueis usually a misspelled key, not a reference problem.
Chapter 7.4 takes the arrow seriously: why it exists, where it is optional, and the one place it absolutely is not.
Where this fits
Part of the Perl curriculum.
