Skip to content
VLSI Mentor

Perl Part I · Module 7 · References

Arrow Notation, and When You Can Omit It

The arrow does exactly what Chapter 7.3's braced and bare forms do, and it is the form worth adopting, because it reads left to right in the order you think: this structure, then that key, then that index. Once structures nest more than one level deep the other spellings stop being readable and the arrow does not. There is one genuine rule to learn, and it is small: between two subscripts the arrow is optional, and before the first subscript it is mandatory. Dropping the first arrow does not produce a subtle difference — it silently refers to an entirely different variable, and under use strict that is a compile error naming something you never typed.

Intermediate13 min readPerlPart IReferencesData Structures

Part I · Module 7 · Chapter 7.4 · Arrow Notation, and When You Can Omit It

1. The Arrow

Azvya Education Pvt. Ltd.VLSI Mentor
arrow.pl
use strict;
use warnings;

my @marks = (10, 20, 30);
my %conf  = (retries => 3);

my $aref = \@marks;
my $href = \%conf;

printf "array element : %d\n", $aref->[1];
printf "hash value    : %d\n", $href->{retries};
printf "last element  : %d\n", $aref->[-1];
printf "count         : %d\n", scalar(@$aref);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
array element : 20
hash value    : 3
last element  : 30
count         : 3

$aref->[1] reads as "the reference, then element 1". $href->{retries} reads as "the reference, then key retries". Negative indices work, because Chapter 5.2's indexing rules apply unchanged once you are through the reference.

Notice the last line still uses scalar(@$aref). The arrow is for reaching one element. For the whole container you still need a sigil and braces — @$aref, @{ $aref }, keys %$href. There is no arrow form for "the whole array", which is the one gap in the notation and a common point of confusion.

TaskArrow?
one array element$aref->[0] ✓
one hash value$href->{key} ✓
the whole array@$aref — no arrow form
the element countscalar(@$aref) — no arrow form
the last index$#$aref — no arrow form
the keyskeys %$href — no arrow form

2. Four Spellings, One Element

Azvya Education Pvt. Ltd.VLSI Mentor
arrow-chain.pl
use strict;
use warnings;

my $table = [ [1, 2], [3, 4] ];

printf "every arrow    : %d\n", $table->[1]->[0];
printf "arrows dropped : %d\n", $table->[1][0];
printf "bare form      : %d\n", $$table[1][0];
printf "braced form    : %d\n", ${ $table }[1][0];
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
every arrow    : 3
arrows dropped : 3
bare form      : 3
braced form    : 3

All four reach row 1, column 0 of a two-by-two table. They are the same element, and 3 is the value in all four cases.

The second line is the one to write. $table->[1][0] keeps the first arrow — which says "this scalar holds a reference" — and drops the second, which would only be noise.

3. The Rule: Optional Between, Mandatory Before

Here is what happens when the first arrow is dropped.

Azvya Education Pvt. Ltd.VLSI Mentor
arrow-first.pl
use strict;
use warnings;

my $table = [ [1, 2], [3, 4] ];

printf "%d\n", $table[0][0];
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
Global symbol "@table" requires explicit package name (did you forget to declare "my @table"?) at arrow-first.pl line 6.
Execution of arrow-first.pl aborted due to compilation errors.
Azvya Education Pvt. Ltd.VLSI Mentor
Measured exit status
255

Read what the error names: @table. Not $table, the scalar on line 5 holding the reference — @table, an array that does not exist anywhere in the program.

$table[0] means "element 0 of the array @table". That is simply what the syntax means, and it has nothing to do with the scalar $table. Chapter 5.1 established that $x and @x are unrelated variables that merely share a name; this is that fact arriving with consequences.

4. Depth, and Why the Arrow Wins

Three levels, arrows dropped after the first:

Azvya Education Pvt. Ltd.VLSI Mentor
deep.pl
use strict;
use warnings;

my $design = {
    blocks => {
        alu => { ports => ["clk", "rst", "a", "b"] },
    },
};

printf "port count : %d\n", scalar(@{ $design->{blocks}{alu}{ports} });
printf "third port : %s\n", $design->{blocks}{alu}{ports}[2];
print  "in a string: $design->{blocks}{alu}{ports}[2]\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
port count : 4
third port : a
in a string: a

$design->{blocks}{alu}{ports}[2] is four lookups in a row and still reads in one pass: design, blocks, alu, ports, index 2. Compare the braced equivalent for the same element:

Azvya Education Pvt. Ltd.VLSI Mentor
The same element, braced throughout
${ ${ ${ $design }{blocks} }{alu} }{ports}[2]

That is correct and nobody should write it. The nesting runs inside-out, so finding the first lookup means counting braces from the middle. This is the whole case for the arrow.

Two details from that output worth keeping:

  • The chain interpolates. Line three put $design->{blocks}{alu}{ports}[2] straight into a double-quoted string and got a. That makes report lines readable without a pile of sprintf arguments.
  • The whole container still needs braces. Line one is scalar(@{ $design->{blocks}{alu}{ports} }) — arrow chain to reach the reference, then @{ } around all of it to get the array. This combination is the normal idiom and is worth recognising on sight: arrow to navigate, braces to open the final container.

5. Where Else the Arrow Appears

The arrow has one other use in Part I: calling a code reference.

Azvya Education Pvt. Ltd.VLSI Mentor
Named here, covered in Chapter 7.11
$cref->();           # call the subroutine that $cref refers to
$dispatch->{read}->( $addr );

Same idea — go through the reference — with parentheses instead of a subscript. Chapter 7.11 is the chapter on it, including why a dispatch table beats a long if/elsif chain.

6. Why This Matters in Engineering Work

Every report parser you write ends up arrow-heavy. A timing report becomes $paths->[$i]{slack}, a netlist becomes $cells->{$name}{type}, a coverage summary becomes $cov->{$grp}{bins}[$j]{hits}. The arrow is what keeps those readable at a glance six months later.

The one rule prevents one real bug, and a compiler catches it. Dropping the first arrow is a compile error naming a variable you never wrote, which is the single most helpful kind of failure. Recognising that error message — "@table requires explicit package name" when you only ever wrote $table — turns a confusing minute into five seconds.

And the arrow-plus-braces combination is worth making automatic. @{ $h->{list} } appears in essentially every script that walks a structure. Reading it as two separate acts — navigate with arrows, then open with braces — is what makes the deeper chapters in this module straightforward instead of fiddly.

7. Common Mistakes

Dropping the first arrow. $table[0][0] refers to @table. Compile error under use strict.

Looking for an arrow form for the whole container. There is none. Use @$aref, @{ $aref }, keys %$href.

Writing every arrow in a long chain. $a->{b}->{c}->{d} is legal and noisy. Keep the first, drop the rest.

Bracing a whole chain inside-out. Correct, unreadable, and unnecessary.

Forgetting @{ } around an arrow chain used as a list. for my $p (@{ $d->{ports} }), not for my $p ($d->{ports}) — the second iterates once, over the reference itself.

Assuming $x and @x are related. They are not, which is exactly why the first arrow is mandatory.

8. Exercise

Exercise 1 — the basics. Take references to a three-element array and a one-key hash. Print an element with ->[ ], a value with ->{ }, and the last element with a negative index.

Exercise 2 — no arrow form. For the same array reference, print the element count, the last index, and the whole array. Note which of the three used an arrow, and why.

Exercise 3 — four spellings. Build my $table = [ [1,2], [3,4] ]; and print row 1 column 0 four ways: every arrow, arrows dropped, bare, braced. Confirm all four agree.

Exercise 4 — the mandatory arrow. Write $table[0][0] and record the exact error and exit status. Then say, in one sentence, which variable the error named and why that variable does not exist.

Exercise 5 — depth. Build the three-level $design structure from §4. Print the port count, the third port, and the third port interpolated inside a sentence. Then write the same element using braces throughout and decide which you would put in a shared script.

Exercise 6 — the combination. Loop over @{ $design->{blocks}{alu}{ports} } and print each port on its own line, counting the iterations. Then remove the @{ } so the list is just $design->{blocks}{alu}{ports}, and record both the iteration count and the exact text printed. Say in one sentence what that text was.

Exercise 7 — without strict. Take Exercise 4's failing program, remove use strict but keep use warnings, and run it again. Record the value, STDERR, and the exit status. Then print scalar(@table) and ref($table[0]). Write two sentences: one on what the program silently created, and one on which failure you would rather debug.

9. Summary

  • $aref->[0] and $href->{key} reach one element, left to right.
  • There is no arrow form for a whole container. @$aref, scalar(@$aref), $#$aref, keys %$href.
  • Between two subscripts the arrow is optional: $table->[1][0] is $table->[1]->[0].
  • Before the first subscript it is mandatory. $table[0][0] refers to @table, a different variable — a compile error under use strict, exit 255.
  • Arrows chain readably to any depth, and the chain interpolates inside double-quoted strings.
  • Navigate with arrows, open the final container with braces: @{ $d->{blocks}{alu}{ports} }.
  • The arrow also calls a code reference — $cref->() — which Chapter 7.11 covers.

Chapter 7.5 removes the named variables entirely: [ ] and { } build an array or a hash and hand you back a reference in one step, which is how nested structures are actually written.

Where this fits

Part of the Perl curriculum.