Perl Part I · Module 5 · Arrays and Lists
Lists vs Arrays
This module has been using two words as though they were interchangeable, and they are not. A list is a sequence of values that an expression produces while it runs — the parenthesised thing on the right of an assignment, what a function hands back, what a range operator generates. An array is a named variable that stores one. The difference is not pedantry: it decides what happens when you ask either of them for a single value, and the two answers are nothing alike. An array asked for one value reports how many elements it holds. A list asked for one value hands over its last element and discards the rest. Once that lands, the rules that looked arbitrary earlier in the module stop being arbitrary.
Foundation15 min readPerlPart IFundamentalsArraysContext
Part I · Module 5 · Chapter 5.6 · Lists vs Arrays
1. Two Words, Two Things
- A list is a sequence of values produced by an expression.
("a", "b", "c")is a list. So issplit /,/, $line,1 .. 10,sort @names, and@awhen it is used where several values are wanted. A list has no name and does not persist — it exists while the expression is being evaluated. - An array is a named variable that stores a list.
@blocksis an array. It has a name, it persists, and you can change it.
The relationship is that an array is assigned a list:
my @blocks = ("alu", "fifo", "decoder");
# ^array ^listEverything in this chapter follows from the fact that one of these is a container and the other is not.
2. Ask Each for One Value and They Differ
use strict;
use warnings;
my @a = ("a", "b", "c");
my $from_array = @a;
print "from the array : $from_array\n";from the array : 3use strict;
use warnings;
my $from_list = ("a", "b", "c");
print "from the list : $from_list\n";from the list : cUseless use of a constant ("a") in void context at from-list.pl line 4.
Useless use of a constant ("b") in void context at from-list.pl line 4.3 from the array. c from the list. Same three values.
- The array in scalar context reports its count. That is Chapter 5.7's whole subject, and it is the behaviour you will use constantly.
- The list in scalar context evaluates its elements in order and produces the last one. The first two went nowhere — and Perl says so, twice:
Useless use of a constant ("a") in void context. Those two warnings are the diagnostic telling you that two of your three values were discarded.
That warning pair is worth noticing because it only appears for constants. With variables or function calls on the left, Perl cannot tell they are useless and stays silent — so the discarding happens without a word.
3. The Fork, Drawn
One list, two destinations, two different kinds of answer
4. A List Is Not a Container, and the Parser Enforces It
use strict;
use warnings;
push ("a", "b"), "c";Type of arg 1 to push must be array (not constant item) at push-to-list.pl line 4, near ""b")"
Execution of push-to-list.pl aborted due to compilation errors.That is a compile error, not a runtime one. push requires an array because it modifies something, and there is nothing to modify in a list — the list is a value in flight, not a place.
The same applies to pop, shift, unshift, splice and $#. All of them need a variable.
This is the sharpest statement of the distinction available: Perl's own parser refuses.
5. But a List Can Be Sliced
Here is the fact that makes the distinction genuinely confusing rather than merely subtle.
use strict;
use warnings;
my $second = ("a", "b", "c")[1];
my @two = ("a", "b", "c", "d")[1, 3];
print "list[1] : $second\n";
print "list[1,3] : @two\n";list[1] : b
list[1,3] : b dA list slice subscripts a list directly, with no array involved. So lists support subscripting but not length, which is not an obvious combination.
The reason it works is that a slice is a read — it selects from values that exist during the expression — while $# and push need a variable to inspect or change. Reading from a list in flight is possible; asking it about itself is not.
This is genuinely useful for taking one item out of a function's return value without storing the whole thing:
use strict;
use warnings;
my $line = "alu,smoke,PASS,184";
my $status = (split /,/, $line)[2];
print "status: $status\n";status: PASSOne field out of four, no intermediate array. The parentheses around the split are required — they make it a list that can be subscripted.
6. List Assignment, and Both Mismatches Are Silent
Assigning a list to a list of variables distributes the values positionally:
use strict;
use warnings;
my ($block, $test, $status) = ("alu", "smoke", "PASS");
printf "block=%s test=%s status=%s\n", $block, $test, $status;block=alu test=smoke status=PASSThat is the form Chapter 5.4 §5 used with split, and it is the readable way to name the fields of a row.
What happens when the counts do not match:
use strict;
use warnings;
my ($x, $y) = ("a", "b", "c");
printf "two from three : x=%s y=%s\n", $x, $y;
my ($p, $q, $r) = ("a", "b");
printf "three from two : p=%s q=%s r=%s\n", $p, $q, (defined $r ? $r : "undef");two from three : x=a y=b
three from two : p=a q=b r=undefBoth mismatches are silent. Extra values on the right are discarded; missing ones leave the left-hand variables undef.
That is the same behaviour as Chapter 5.3 §4's slice assignment, and it has the same consequence: a row with fewer fields than you destructured gives you undef variables rather than an error. Chapter 5.8 is the chapter about handling that properly.
The one-element parenthesis changes everything
use strict;
use warnings;
my @marks = (72, 65, 90);
my $count = @marks;
my ($first) = @marks;
printf "my \$count = \@marks -> %s\n", $count;
printf "my (\$first) = \@marks -> %s\n", $first;my $count = @marks -> 3
my ($first) = @marks -> 72Two statements differing by one pair of parentheses, giving 3 and 72.
my $count = @marks is a scalar assignment, so the array is asked for one value and gives its count. my ($first) = @marks is a list assignment, so the array supplies its elements and the first one lands in $first.
This is exactly the review problem Chapter 2.9 opened with, now explicable: the parentheses on the left decide which kind of assignment it is, and therefore what the right-hand side is asked for. Chapter 2.10's advice to state the context explicitly — scalar(@marks) — is the fix.
7. Counting What a List Produced
Since a list has no length, counting what an expression produced takes an idiom:
use strict;
use warnings;
my $n = () = ("a", "b", "c", "d");
my @nums = (1, 2, 3, 4, 5);
my $over = () = grep { $_ > 2 } @nums;
printf "literal list : %d\n", $n;
printf "grep matches : %d\n", $over;literal list : 4
grep matches : 3my $n = () = LIST is read right to left: the list is assigned to an empty list, and a list assignment evaluated in scalar context produces the number of elements on its right. So $n gets the count.
It is an odd-looking construct — sometimes called the "countof" idiom — and it is worth recognising. grep is Chapter 5.10's.
8. Why This Matters in Engineering Work
It explains the rules that looked arbitrary. Why scalar(@a) works and there is no scalar() of a list's length; why push needs a variable; why my ($x) = f() and my $x = f() differ. All one distinction.
Destructuring a parsed row is list assignment. my ($block, $test, $status) = split /,/, $line; is the most readable way to name fields, and §6's silence on a short row is the thing to guard.
The list slice saves an intermediate array when you want one field: (split /,/, $line)[2]. Worth knowing, and worth not overusing — if you need three fields, destructure them with names.
And the count-of trap generalises. §7's split case is specific, but the principle is not: a function's behaviour in scalar context is a documented property of that function, not something to assume. Chapter 2.9 said context is not a conversion applied afterwards; this is what that means in practice.
9. Common Mistakes
Expecting a list in scalar context to give a count. It gives the last element. Only an array gives a count.
Trying to push onto a list. Compile error — push needs a variable.
Assuming a list has no subscripting. It does: ("a","b","c")[1]. It has no length.
Forgetting the parentheses around a list slice. split /,/, $line[2] subscripts $line, not the result.
Expecting a count mismatch in a list assignment to warn. Both directions are silent.
Confusing my $x = @a with my ($x) = @a. The first is the count, the second is the first element.
Using the count-of idiom on split. It reports 1. Use split in scalar context, or store and count.
10. Exercise
Exercise 1 — the two answers. Assign the same three values to an array and read one value from it; then use the literal list in a scalar assignment. Print both results and record the two warnings from the second case.
Exercise 2 — the parser refuses. Try to push onto a parenthesised list. Record the exact compile error and the exit status. Then name three other functions from this module that would fail the same way.
Exercise 3 — slice a list. Take the third field out of "alu,smoke,PASS,184" with a list slice and no intermediate array. Then remove the parentheses around the split and record what changes.
Exercise 4 — destructure a row. Split "fifo,wr,FAIL,92" into four named variables with one list assignment. Then do it with only three variables on the left, and with five, reporting what happens to the extra and the missing in each case.
Exercise 5 — one pair of parentheses. With a four-element array, write my $a = @arr; and my ($b) = @arr; and print both. Explain the difference in one sentence using the words "scalar assignment" and "list assignment".
Exercise 6 — count what grep produced. Use the count-of idiom to count how many of (1..10) are greater than 6. Confirm you get 4.
Exercise 7 — the split trap. Use the count-of idiom on split /,/, "a,b,c,d" and record what you get. Then run perl -MO=Deparse on that line and quote the limit Perl added. Finally, get the correct count two different ways.
11. Summary
- A list is a sequence of values an expression produces; an array is a named variable that stores one.
- An array in scalar context gives its count; a list gives its last element — and discards the rest, warning only when they are constants.
- A list is not a container.
pushon a list is a compile error, as arepop,shift,spliceand$#. - A list can be sliced —
("a","b","c")[1]— so it supports subscripting but not length. (split /,/, $line)[2]takes one field with no intermediate array.- List assignment distributes positionally, and both too-many and too-few are silent.
my $x = @ais the count;my ($x) = @ais the first element. One pair of parentheses.my $n = () = LISTcounts what a list produced — but not forsplit, where the optimiser adds a limit of 1. Usesplitin scalar context, or store and count.
Chapter 5.7 takes the array half of §2 and makes it a tool: the places Perl supplies scalar context automatically, and why that turns "did anything fail" into a two-word test.
Where this fits
Part of the Perl curriculum.
