Skip to content
VLSI Mentor

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

Azvya Education Pvt. Ltd.VLSI Mentor
anon.pl
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];
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
[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 wantNamed, two stepsAnonymous, one step
an array referencemy @a = (1,2); my $r = \@a;my $r = [1,2];
a hash referencemy %h = (k=>1); my $r = \%h;my $r = {k=>1};
an empty array referencemy @a; my $r = \@a;my $r = [];
an empty hash referencemy %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.

Azvya Education Pvt. Ltd.VLSI Mentor
copy-vs-ref.pl
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);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
@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:

Azvya Education Pvt. Ltd.VLSI Mentor
hash-copy.pl
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);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
%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.

Azvya Education Pvt. Ltd.VLSI Mentor
nested.pl
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} });
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
blocks      : alu fifo
retries     : 3
matrix[1][0]: 3
block count : 2

Written 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.

Azvya Education Pvt. Ltd.VLSI Mentor
records.pl
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};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
alu    -0.12  1840 FAIL
fifo   +0.34   920 pass
regf   -0.05  2310 FAIL
failing: 2 of 3
worst  : alu at -0.12

An ordinary array of hash references — a table of records, each row a named set of fields. Three things to notice:

  • @rows is a plain array, not a reference. The references are its elements. That is why for my $r (@rows) needs no dereferencing, while $r->{block} does.
  • grep and sort work unchanged. Chapter 5.10's grep takes 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.

Azvya Education Pvt. Ltd.VLSI Mentor
A hash constructor inside map — measured
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);    # works
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — the shape that fails
my @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

Azvya Education Pvt. Ltd.VLSI Mentor
empty-truth.pl
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");
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
empty aref : true
empty href : true
but @$a is false

Chapter 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], never my @aref.
  • [ @a ] is a copy; \@a is an alias. The copy puts @a in 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, sort and map work on it unchanged.
  • { is ambiguous with a block. map { { k => $_ } } works, map { k => $_ } does not, and keys %{ {} } 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.