Skip to content
VLSI Mentor

Perl Part I · Module 6 · Hashes

Constructing a Hash, and the Fat Comma

Chapter 6.1 built a hash from a flat list of quoted keys and values, which works and makes a reader count commas to see which items are which. Perl has a better notation: a comma with an equals sign in front of it, which behaves exactly like a comma except that it also quotes the bareword on its left. The result is a literal whose pairing is visible rather than inferred, and it is what you will see in every modern Perl codebase. The chapter also covers what happens when the list of pairs turns out to have an odd number of items in it — which is not an error, and not silent either — and one fact about keys that explains a class of lookup failure: a key is always a string, so two keys that look like different numbers can turn out to be the same key.

Foundation13 min readPerlPart IFundamentalsHashesReadability

Part I · Module 6 · Chapter 6.2 · Constructing a Hash, and the Fat Comma

1. A Hash Is Built From a Flat List

Azvya Education Pvt. Ltd.VLSI Mentor
flat-list.pl
use strict;
use warnings;

my %marks = ("maths", 72, "physics", 65, "chemistry", 90);

printf "keys: %d\n", scalar(keys %marks);
printf "maths: %d\n", $marks{maths};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
keys: 3
maths: 72

There is no special hash syntax on the right-hand side. It is an ordinary list — Chapter 5.6's kind — and the hash assignment reads it as alternating keys and values: item 1 is a key, item 2 is its value, item 3 is the next key, and so on.

Which means a hash can be built from anything that produces a list, including an array:

Azvya Education Pvt. Ltd.VLSI Mentor
from-an-array.pl
use strict;
use warnings;

my @pairs = ("alu", "PASS", "fifo", "FAIL");

my %status = @pairs;

printf "keys: %s\n", join(" ", sort keys %status);
printf "fifo: %s\n", $status{fifo};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
keys: alu fifo
fifo: FAIL

Four elements became two pairs. That conversion runs both ways and is Chapter 6.10's subject.

The problem with the flat form is readability. In ("maths", 72, "physics", 65, "chemistry", 90) nothing marks where one pair ends and the next begins — you work it out by counting from the left. Add a fourth subject and the line gets longer and no clearer.

2. => Is a Comma That Quotes

Azvya Education Pvt. Ltd.VLSI Mentor
fat-comma.pl
use strict;
use warnings;

my %marks = (
    maths     => 72,
    physics   => 65,
    chemistry => 90,
);

printf "keys: %d\n", scalar(keys %marks);
printf "maths: %d\n", $marks{maths};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
keys: 3
maths: 72

=> — the fat comma, sometimes called the fat arrow — does two things:

  1. It separates list items, exactly like a comma.
  2. It quotes the bareword immediately to its left, so maths becomes "maths" without you writing the quotes.

The second job is why the keys above need no quoting. And the formatting it enables is the real gain: one pair per line, with the => showing which side is which. A reader can see the structure instead of reconstructing it.

Note the trailing comma after the last pair. Perl allows it, and it means adding a fourth subject is a one-line diff rather than a two-line one. That is worth doing.

Without =>, a bareword key is a compile error

Azvya Education Pvt. Ltd.VLSI Mentor
bareword-key.pl
use strict;
use warnings;

my %marks = (maths, 72);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
Bareword "maths" not allowed while "strict subs" in use at bareword-key.pl line 4.
Execution of bareword-key.pl aborted due to compilation errors.

A bare word with nothing to quote it is not a string — Perl has no idea what maths is meant to be, and use strict refuses to guess. That is Chapter 1.10's third restriction, strict subs, and it is why Chapter 6.1's flat-list example had to quote its keys.

So the three ways to write a key are:

FormWorks?
maths => 72yes — => quotes it
"maths", 72yes — quoted explicitly
maths, 72no — compile error under use strict

=> only quotes a bareword

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

my %opt = (max-retries => 3);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
Bareword "max" not allowed while "strict subs" in use at hyphenated.pl line 4.
Execution of hyphenated.pl aborted due to compilation errors.

Read which word Perl objected to: max, not max-retries. The hyphen is the subtraction operator, so Perl read max as one bareword and retries as another with a minus between them — and => only reached as far back as retries. Neither bareword is quoted, so strict subs refused the first one it got to.

A key containing anything other than letters, digits and underscores must therefore be quoted:

Azvya Education Pvt. Ltd.VLSI Mentor
hyphenated-fixed.pl
use strict;
use warnings;

my %opt = ("max-retries" => 3, max_retries => 3);

printf "keys: %s\n", join(" ", sort keys %opt);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
keys: max-retries max_retries

Both work and they are different keys. The underscore form is the one to prefer in code you control, precisely because it needs no quoting.

3. An Odd Number of Items Warns and Still Builds

Azvya Education Pvt. Ltd.VLSI Mentor
odd-number.pl
use strict;
use warnings;

my %h = ("a", 1, "b");

printf "keys: %d\n", scalar(keys %h);
printf "a = %s\n", $h{a};
printf "b = %s\n", (defined $h{b} ? $h{b} : "undef");
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDOUT
keys: 2
a = 1
b = undef
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
Odd number of elements in hash assignment at odd-number.pl line 4.

Three items, so one pair is incomplete. Perl warns and builds the hash anyway, giving the final key a value of undef.

Note what that means: the hash has two keys, and b exists with no value. That is a different state from b not existing at all, and telling those apart is exactly Chapter 6.4's subject.

4. Keys Are Always Strings

This explains a class of lookup failure that otherwise looks inexplicable.

Azvya Education Pvt. Ltd.VLSI Mentor
keys-are-strings.pl
use strict;
use warnings;

my %h;

$h{1}   = "set as a number";
$h{"1"} = "set as a string";

printf "key count : %d\n", scalar(keys %h);
printf "value     : %s\n", $h{1};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
key count : 1
value     : set as a string

One key. $h{1} and $h{"1"} are the same key, so the second assignment overwrote the first.

A hash key is always a string. A number used as a key is converted to its string form first — the stringification from Chapter 2.6 — and that string is the key.

Which produces this:

Azvya Education Pvt. Ltd.VLSI Mentor
numeric-keys.pl
use strict;
use warnings;

my %h;

$h{1}     = "integer one";
$h{1.0}   = "float one";
$h{"1.0"} = "string one point zero";

printf "key count : %d\n", scalar(keys %h);
for my $k (sort keys %h) {
    printf "  [%s] = %s\n", $k, $h{$k};
}
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
key count : 2
  [1] = float one
  [1.0] = string one point zero

Two keys, not three. The number 1.0 stringifies to "1", so it collided with the integer 1 and overwrote it. But the string "1.0" was already a string and stayed "1.0", which is a different key.

So:

  • Numeric keys are normalised by stringification. 1, 1.0, 1.00 and 1e0 all become the key "1".
  • String keys are not normalised at all. "1.0" stays exactly "1.0".

The practical consequence is for data read from a file, which Chapter 4.1 established arrives as text. A column containing 1.0 gives you the string "1.0", so a lookup written as $h{1} will not find it — and by Chapter 6.1 §5 that miss is silent.

Azvya Education Pvt. Ltd.VLSI Mentor
the-real-bug.pl
use strict;
use warnings;

my @parsed = split /,/, "1.0,PASS";

my %h = ($parsed[0] => $parsed[1]);

printf "stored under    : [%s]\n", (keys %h)[0];
printf "lookup \$h{1}    : [%s]\n", (defined $h{1}     ? $h{1}     : "undef");
printf "lookup \$h{1.0}  : [%s]\n", (defined $h{1.0}   ? $h{1.0}   : "undef");
printf "lookup \$h{\"1.0\"}: [%s]\n", (defined $h{"1.0"} ? $h{"1.0"} : "undef");
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
stored under    : [1.0]
lookup $h{1}    : [undef]
lookup $h{1.0}  : [undef]
lookup $h{"1.0"}: [PASS]

Two of the three lookups fail. The fix is to normalise keys on the way in — the discipline from Chapter 4.6 §6, now applied to keys rather than values. If a parsed field is a number, make it one with 0 + $field before using it as a key, so that every lookup goes through the same conversion.

5. Building a Hash From Parsed Data

Putting the chapter together with Module 5:

Azvya Education Pvt. Ltd.VLSI Mentor
from-rows.pl
use strict;
use warnings;

my @rows = ("alu,PASS", "fifo,FAIL", "decoder,PASS");

my %status;

for my $row (@rows) {
    my @field = split /,/, $row, -1;
    next if scalar(@field) != 2;

    my ($name, $result) = @field;
    $status{$name} = $result;
}

printf "built %d entries\n", scalar(keys %status);
printf "fifo : %s\n", $status{fifo};
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
built 3 entries
fifo : FAIL

The guard from Chapter 5.8 is doing its job before anything reaches the hash, which matters more here than it did for an array: a short row would give $status{$name} = undef, creating a key with no value — §3's state, reached by a different route.

Note $status{$name} = $result; needs no => because the key is a variable, not a bareword. => is for literal keys in a list; assignment by key uses whatever expression you like inside the braces.

6. Why This Matters in Engineering Work

Configuration literals. A hash of settings is the commonest hand-written hash, and the one-pair-per-line form with => is what keeps it reviewable as it grows. The trailing comma means adding a setting touches one line.

The shifted-pair bug is the expensive one. §3's callout is the shape: a deleted value re-pairs everything after it, so several settings silently take each other's values. Nothing is missing, so a count check passes; the values are just wrong. One pair per line is what makes the deletion visible in a diff.

Keys built from parsed data need normalising. A key that arrived as text is a text key, and 1.0 from a CSV will not be found by $h{1}. Decide once, at the point of parsing, whether a key is a number or a label — the same decision Chapter 3.5 §5 required for comparisons, now for key identity.

And the odd-number warning is worth treating as fatal. It means the literal you are reading is not the literal you think you are reading. Module 14 covers making warnings fatal; until then, read them.

7. Common Mistakes

Using a bareword key without =>. Compile error under use strict.

Using => with a hyphenated key. max-retries => 3 is a syntax error; quote it or use underscores.

Dropping a value from a hash literal. Everything after it re-pairs. The odd-number warning fires only when the total becomes odd.

Expecting 1 and "1.0" to be the same key. 1 and 1.0 are; "1.0" is not.

Looking up a parsed numeric key without normalising it. The stored key is text and the miss is silent.

Writing => where the key is a variable. $h{$name} = $v is the form; => is for literal keys in a list.

Omitting the trailing comma. Harmless, but it makes every addition a two-line diff.

8. Exercise

Exercise 1 — both notations. Build the same four-pair hash twice, once with quoted keys and plain commas and once with =>, one pair per line. Confirm the key counts match, then say which you would commit and why in one clause.

Exercise 2 — the bareword error. Write my %h = (maths, 72); and run it. Record the exact message and the exit status, then fix it two different ways.

Exercise 3 — the hyphen. Write my %o = (max-retries => 3); and record what happens. Then write the two forms that work and confirm they produce different keys.

Exercise 4 — the odd number. Build a hash from five items. Record the warning, the key count, and which key is undefined. Then say what the exit status was.

Exercise 5 — the shifted pair. Take a four-pair literal and delete one value, leaving its key. Print every key and value. Report how many pairs are wrong and whether the key count changed.

Exercise 6 — numeric key identity. Store values under 1, 1.0, "1", "1.0" and 1e0 in one hash. Print the key count and every key with its value. Account for the count.

Exercise 7 — the parsed key. Split "2.0,FAIL" on the comma, use field 0 as a key, then try to look it up with $h{2}, $h{2.0} and $h{"2.0"}. Report which succeed, then add a normalising step so a numeric lookup works.

9. Summary

  • A hash is assigned from a flat list read as alternating keys and values, so anything producing a list can build one.
  • => is a comma that also quotes the bareword on its left, which is what lets a literal show its own pairing.
  • A bareword key without => is a compile error under use strict.
  • => only quotes a bareword — a hyphenated key is a syntax error and must be quoted.
  • A trailing comma is legal and makes additions one-line diffs.
  • An odd number of items warns — Odd number of elements in hash assignment — and still builds the hash with the last key set to undef.
  • A dropped value re-pairs everything after it, and the warning fires only if the total becomes odd.
  • Keys are always strings. Numeric keys are normalised by stringification, so 1 and 1.0 are one key, while the string "1.0" is another.
  • Normalise keys built from parsed data, or a numeric lookup silently misses a text key.

Chapter 6.3 covers changing a hash after it is built — adding, overwriting and removing entries — and the difference between removing a key and emptying it.

Where this fits

Part of the Perl curriculum.