Perl Part I · Module 7 · References
Anonymous Arrays and Hashes: [] and {}
Everything so far has gone through a named variable: declare an array, then take a reference to it. That middle step is usually unnecessary. Square brackets build an array and give you a reference to it in one expression, and curly braces do the same for a hash — which is how every nested structure in real Perl is actually written. The constructors also answer a question Chapter 7.2 left open, because there is a real difference between a reference to an existing array and a new array holding the same values. One of them shares; the other does not. Knowing which is which is the difference between a subroutine that modifies its caller's data and one that does not.
Intermediate16 min readPerlPart IReferencesData Structures
Part I · Module 7 · Chapter 7.5 · Anonymous Arrays and Hashes: [] and {}
1. Two Constructors
use strict;
use warnings;
my $aref = [1, 2, 3];
my $href = { retries => 3, timeout => 45 };
my $empty_a = [];
my $empty_h = {};
printf "[1,2,3] is a %s reference, %d elements\n", ref($aref), scalar(@$aref);
printf "{k=>v} is a %s reference, %d keys\n", ref($href), scalar(keys %$href);
printf "[] is a %s reference, %d elements\n", ref($empty_a), scalar(@$empty_a);
printf "{} is a %s reference, %d keys\n", ref($empty_h), scalar(keys %$empty_h);
printf "[1..5] has %d elements, last %d\n", scalar(@{ [1..5] }), [1..5]->[-1];[1,2,3] is a ARRAY reference, 3 elements
{k=>v} is a HASH reference, 2 keys
[] is a ARRAY reference, 0 elements
{} is a HASH reference, 0 keys
[1..5] has 5 elements, last 5[ ... ] builds a new array and returns a reference to it. { ... } builds a new hash and returns a reference to it. There is no named variable anywhere — which is why these are called anonymous.
Note the sigils in that code. $aref is a scalar holding a reference, so the declaration is my $aref = [1,2,3], not my @aref. This is the point where the two notations have to coexist in your head: [ and ] look like an array, and the thing they produce is a scalar.
| What you want | Named, two steps | Anonymous, one step |
|---|---|---|
| an array reference | my @a = (1,2); my $r = \@a; | my $r = [1,2]; |
| a hash reference | my %h = (k=>1); my $r = \%h; | my $r = {k=>1}; |
| an empty array reference | my @a; my $r = \@a; | my $r = []; |
| an empty hash reference | my %h; my $r = \%h; | my $r = {}; |
Ranges work inside the brackets, as the last line shows — [1..5] is a five-element array reference, built from Chapter 3.10's range operator.
2. [ @a ] Is a Copy. \@a Is Not.
This is the most useful thing on the page.
use strict;
use warnings;
my @a = (1, 2);
my $alias = \@a; # refers to @a
my $copy = [ @a ]; # a NEW array holding @a's values
push @$alias, 99;
printf "\@a : %d [%s]\n", scalar(@a), join(" ", @a);
printf "\\\@a ref : %d [%s]\n", scalar(@$alias), join(" ", @$alias);
printf "[ \@a ] copy : %d [%s]\n", scalar(@$copy), join(" ", @$copy);@a : 3 [1 2 99]
\@a ref : 3 [1 2 99]
[ @a ] copy : 2 [1 2]One push, two outcomes. @a and $alias are the same array — they both show three elements. $copy is a different array that happened to be filled from @a's values at the moment it was built, and it still has two.
The same distinction for hashes:
use strict;
use warnings;
my %h = (a => 1);
my $alias = \%h;
my $copy = { %h };
$alias->{b} = 2;
printf "%%h : %d key(s)\n", scalar(keys %h);
printf "\\%%h ref : %d key(s)\n", scalar(keys %$alias);
printf "{ %%h } copy : %d key(s)\n", scalar(keys %$copy);%h : 2 key(s)
\%h ref : 2 key(s)
{ %h } copy : 1 key(s)The mechanism is worth stating plainly: [ @a ] puts @a in list context. The brackets receive a list of values — 1, 2 — exactly as if you had typed them, and build a fresh array from it. The connection to @a ends there. \@a, by contrast, never looks at the values at all; it refers to the container.
3. Nesting, Which Is the Real Point
Constructors nest, and that is how every structure in the rest of this module gets built.
use strict;
use warnings;
my $design = {
blocks => ["alu", "fifo"],
limits => { retries => 3, timeout => 45 },
matrix => [ [1, 2], [3, 4] ],
};
printf "blocks : %s\n", join(" ", @{ $design->{blocks} });
printf "retries : %d\n", $design->{limits}{retries};
printf "matrix[1][0]: %d\n", $design->{matrix}[1][0];
printf "block count : %d\n", scalar(@{ $design->{blocks} });blocks : alu fifo
retries : 3
matrix[1][0]: 3
block count : 2Written with named variables, that structure would need five declarations and five backslashes. Written with constructors it is one expression that looks like the shape of the data — which is the practical argument for using them.
Reading it back uses Chapter 7.4's rules exactly: arrow to navigate, @{ } around the chain when you want the whole inner container.
4. A List of Records
This pattern is worth seeing in full, because it is the one you will reach for most.
use strict;
use warnings;
my @rows = (
{ block => "alu", slack => -0.12, paths => 1840 },
{ block => "fifo", slack => 0.34, paths => 920 },
{ block => "regf", slack => -0.05, paths => 2310 },
);
for my $r (@rows) {
printf "%-5s %+6.2f %5d %s\n",
$r->{block}, $r->{slack}, $r->{paths},
($r->{slack} < 0 ? "FAIL" : "pass");
}
my @failing = grep { $_->{slack} < 0 } @rows;
printf "failing: %d of %d\n", scalar(@failing), scalar(@rows);
my ($worst) = sort { $a->{slack} <=> $b->{slack} } @rows;
printf "worst : %s at %+.2f\n", $worst->{block}, $worst->{slack};alu -0.12 1840 FAIL
fifo +0.34 920 pass
regf -0.05 2310 FAIL
failing: 2 of 3
worst : alu at -0.12An ordinary array of hash references — a table of records, each row a named set of fields. Three things to notice:
@rowsis a plain array, not a reference. The references are its elements. That is whyfor my $r (@rows)needs no dereferencing, while$r->{block}does.grepandsortwork unchanged. Chapter 5.10'sgreptakes a block that happens to look inside a reference; Chapter 5.9's comparator compares$a->{slack}against$b->{slack}. Nothing about references changes how those functions behave.my ($worst) = sort ...takes the first element of the sorted list by assigning to a one-element list, the idiom from Chapter 5.6 §4.
This is the shape that a parsed timing report, a netlist summary or a coverage table naturally takes, and it is why { } is worth knowing well.
5. The Brace Ambiguity
{ begins a hash constructor. It also begins a block. Perl guesses, and it is usually right, but it is worth knowing where the guess fails.
my @r = map { { name => $_ } } qw(a b); # works: 2 items, first is a HASH
my @r = map {; { name => $_ } } qw(a b); # works
my @r = map { +{ name => $_ } } qw(a b); # worksmy @r = map { name => $_ } qw(a b);
-> syntax error at -e line 1, near "} qw(a b)"The doubled-brace form works: the outer { is map's block, the inner one is a hash constructor, and Perl reads both correctly. The form that fails is the one with no inner braces, where the single { has to be both at once.
So the advice you will see to always write +{ ... } or {; ... } is defensive rather than strictly necessary — but it costs one character and removes a question, which is a reasonable trade in a block that someone else will edit later.
6. Empty Is Still True
use strict;
use warnings;
printf "empty aref : %s\n", ([] ? "true" : "false");
printf "empty href : %s\n", ({} ? "true" : "false");
my $a = [];
printf "but \@\$a is %s\n", (@$a ? "true" : "false");empty aref : true
empty href : true
but @$a is falseChapter 7.1 §6 made this point and it is worth repeating with the constructors in hand, because [] and {} make it very easy to produce an empty-but-true value by accident.
if ($aref) asks "do I have a reference"; if (@$aref) asks "does it contain anything". They are different questions and [] answers them differently. When you want "is there any data", dereference first.
7. Why This Matters in Engineering Work
Constructors are how structures get built from input. Parsing a report line by line, you accumulate push @rows, { block => $1, slack => $2 }; — one constructor per line, no named variables, no backslashes. The alternative with named variables does not work at all, because each iteration would reuse the same array and every row would end up referring to the same data.
The copy-versus-reference distinction decides whether a subroutine is safe. process([ @data ]) hands over a copy of the outer list; process(\@data) hands over the real thing. Both are reasonable; silently choosing the wrong one is how a script modifies the table it was only supposed to summarise.
And an empty structure is a legitimate result that tests as true. A per-block failure list where some blocks have no failures will contain [] values, and if ($failures->{$b}) will say yes to all of them. Reach for if (@{ $failures->{$b} }) when the question is whether anything is in there.
8. Common Mistakes
my @aref = [1,2,3]; — the constructor returns one scalar, so this makes a one-element array containing a reference. Declare it as my $aref.
Expecting [ @a ] to track @a. It is a snapshot of the values. Use \@a to share.
Expecting [ @a ] to copy everything. It copies one level. Inner references are shared.
keys %{ {} } — syntax error, and the message blames an unmatched brace. Write %{ +{} } or use a variable.
map { name => $_ } — syntax error. The doubled form map { { name => $_ } } works.
Reusing one named array for every row in a loop. Every row ends up referring to the same array. Build a constructor inside the loop instead.
if ($aref) to test for contents. An empty [] is true. Dereference first.
9. Exercise
Exercise 1 — the constructors. Build an array reference, a hash reference, an empty one of each, and a reference to [1..5]. For each, print ref(), the element or key count, and for the range the last element.
Exercise 2 — copy or alias. Reproduce §2 exactly. Then change it so the push goes through $copy instead, and record whether @a changes. Write one sentence naming which of the two expressions shares storage.
Exercise 3 — the hash version. Do the same for { %h } against \%h, adding a key through the alias. Report all three key counts.
Exercise 4 — one level deep. Build my @rows = ([1,2],[3,4]); and my $copy = [ @rows ];. Push a third row onto $copy and confirm @rows still has two. Then assign to $copy->[0][0] and report whether $rows[0][0] changed. Explain the difference in one sentence.
Exercise 5 — nesting. Build §3's $design structure in one expression. Print the block list, the retries limit, matrix[1][0], and the block count. Then write out how many my declarations the named-variable version would need.
Exercise 6 — a record table. Build §4's three rows. Print the formatted table, the count of failing blocks, and the worst block. Then add a fourth row with a slack of -0.30 and confirm both summary lines change.
Exercise 7 — the brace trap. Run printf "%d\n", scalar(keys %{ {} }); and record the exact two-line error. Then fix it twice — once with +, once with a variable — and confirm both print 0. Finally run scalar(@{ [] }) and say why it never had the problem.
Exercise 8 — empty but true. Build a hash reference whose values are per-block failure lists, with one block having []. Loop over the keys printing whether $h->{$k} is true and whether @{ $h->{$k} } is true. Say which test you would put in a report script.
10. Summary
[ ... ]builds a new array and returns a reference;{ ... }builds a new hash and returns a reference. One step, no named variable.- The result is a scalar.
my $aref = [1,2,3], nevermy @aref. [ @a ]is a copy;\@ais an alias. The copy puts@ain list context and builds a fresh container from the values.- The copy is one level deep. Inner references are shared — a shallow copy, which Chapter 7.13 covers.
- Constructors nest, and that is how every structure in Chapters 7.6 to 7.10 is written.
- An array of hash references is a table of records, and
grep,sortandmapwork on it unchanged. {is ambiguous with a block.map { { k => $_ } }works,map { k => $_ }does not, andkeys %{ {} }is a syntax error blaming an unmatched brace — use+{ }or a variable.[is never ambiguous.[]and{}are true even though they are empty. Dereference before testing for contents.
Chapter 7.6 puts the constructors to work on the first real nested shape: an array of arrays, the table that Chapter 5.12 could not build.
Where this fits
Part of the Perl curriculum.
