Context: one value or a whole list
The idea that quietly shapes every Perl expression: the same code can mean one value or a whole list, and knowing which one you asked for explains most surprises.
The same expression, two answers
Perl decides what an expression means from where it sits. In a list context it produces a list; in a scalar context it produces one value. Both are ordinary and both are useful, but the answers can be very different.
An array in a list context is its items: my @copy = @scores;. The same array in a scalar context is its count: my $how_many = @scores;. That is the whole idea, and once it is clear, scalar @scores stops looking like a special function and starts looking like an instruction.
Where each context comes from
Assigning to a scalar is a scalar context; assigning to an array or a hash is a list context; and a subroutine call inherits the context of wherever its answer landed. print wants a list, which is why print @scores writes every item, and join wants a list too.
A few functions genuinely behave differently when asked for one value. reverse in a scalar context turns the list into one long string and reverses its characters, rather than the order of the items — the example below shows both in three lines.
Asking for the answer you want
The word scalar says "one value, please", whatever the surroundings want, which is how scalar keys %ages counts the keys of a hash. Inside a subroutine you can also ask which context you were called in with wantarray, though a well-named subroutine rarely needs to: answering with a list and letting the caller decide is usually clearer.
The habit worth taking from this chapter is suspicion. When an expression answers something odd, the first question to ask is which context it landed in — and the fix is usually one scalar, or a pair of parentheses around the right part.
Context travels outward from the assignment
The left side of an assignment decides what the right side should produce. Assign to a scalar and the right side is asked for one value; assign to an array or a hash and it is asked for a list. A function call inside that expression inherits the same request, which is why context is described as travelling outward.
print asks its arguments for a list, so print @scores writes every item. scalar overrides the surroundings and asks for one value, and a pair of parentheses can ask for a list where a scalar was expected. Most context bugs are one of those two corrections away from being fixed. The same expression can therefore be correct in one place and wrong in another without changing a character.
Asking a subroutine what it was called for
wantarray answers true when the caller wants a list, false when it wants one value, and undef when the answer is being thrown away. A subroutine can use that to return a list in one case and a count in the other, which is convenient when both answers are useful and confusing when they are not.
The safer habit is to return a list and let the caller decide. my @all = names(); gets the items, my $n = names(); gets the last item rather than the count, and my $n = scalar names(); says what it means. If a count is a genuinely different answer, give it a different subroutine name.
A list in a condition
A condition is a scalar context, so if (@scores) asks for the count and is true when the list is not empty. That is the shortest emptiness test in the language, and it works for a hash too: if (%ages) is true when there is at least one pair.
The same rule means my $first = @scores; gives the count rather than the first item. Reading a list where one value was expected is the mistake this chapter exists to prevent.
One list, asked two questions
use strict;
use warnings;
my @scores = (72, 95, 60);
my @copy = @scores; # list context
my $count = @scores; # scalar context
print "copy: ", join(' ', @copy), "\n";
print "count: $count\n";
print "as a list: ", join(', ', @scores), "\n";
print "as one value: ", scalar @scores, "\n";
my @backwards = reverse @scores;
my $as_text = reverse @scores;
print "list: ", join(' ', @backwards), "\n";
print "text: $as_text\n";
my %seen;
$seen{$_}++ foreach @scores;
print "keys: ", join(', ', sort keys %seen), "\n";Four readings, asked two ways
Run it and compare the last two lines carefully — they come from the same expression. Then add a line that prints the readings joined by commas, and one that prints them in scalar context.
A common surprise is my $n = @list; putting the count in the variable rather than the first item. If you wanted the first item, ask for it by position: $list[0]. There is no automatic "just one thing" to fall back on.
Three context traps catch almost everyone. my $n = @list gives the count, not the first item. my $n = %hash gives internal bucket statistics, not the number of keys; use scalar keys %hash. And reverse @list in scalar context joins the items and reverses the characters, which looks like a sorting bug but is the context doing exactly what it was asked.
Try these next
- Write a subroutine that returns a list in list context and its count in scalar context, then call it both ways.
- Print
reverseof a short list in both contexts, side by side. - Force a scalar with
scalarwhere an array would otherwise hand back its count, and explain the difference.
One subroutine, two answers
Run it and compare the list with the count. Then add a word to the list and check that both answers change together.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does my $n = @scores; put in $n?
