Now that we've talked about context, we can talk about list literals and how they behave in context. You've already seen some list literals. List literals are denoted by separating individual values by commas (and enclosing the list in parentheses where precedence requires it). Because it (almost) never hurts to use extra parentheses, the syntax diagram of a list value is usually indicated like this:
(LIST
)
Earlier we said that LIST
in a syntax
description indicates something that supplies list context to its
arguments, but a bare list literal itself is the one partial exception
to that rule, in that it supplies a list context to its arguments only
when the list as a whole is in list context. The value of a list
literal in list context is just the values of the arguments in the
order specified. As a fancy sort of term in an expression, a list
literal merely pushes a series of temporary values onto Perl's stack,
to be collected off the stack later by whatever operator wants the
list.
In a scalar context, however, the list literal doesn't really
behave like a LIST
, in that it doesn't
supply list context to its values. Instead, it merely evaluates each
of its arguments in scalar context, and returns the value of the final
element. That's because it's really just the C comma operator in
disguise, which is a binary operator that always throws away the value
on the left and returns the value on the right. In terms of what we
discussed earlier, the left side of the comma operator really provides
a void context. Because the comma operator is left associative, if you
have a series of comma-separated values, you always end up with the
last value because the final comma throws away whatever any previous
commas produced. So, to contrast the two, the list assignment:
@stuff = ("one", "two", "three");
assigns the entire list value to array
@stuff
, but the scalar assignment:
$stuff = ("one", "two", "three");
assigns only the value "three
" to variable
$stuff
. Like the @files
array we
mentioned earlier the comma operator knows whether it is in a scalar
or list context, and chooses its behavior accordingly.
It bears repeating that a list value is different from
an array. A real array variable also knows its context, and in a list
context, it would return its internal list of values just like a list
literal. But in a scalar context it returns only the length of the
array. The following assigns to $stuff
the value
3:
@stuff = ("one", "two", "three"); $stuff = @stuff;
If you expected it to get the value "three
",
you were probably making a false generalization by assuming that Perl
uses the comma operator rule to throw away all but one of the
temporary values that @stuff
put on the stack. But
that's not how it works. The @stuff
array never put
all its values on the stack. It never put any of its values on the
stack, in fact. It only put one value, the length of the array,
because it knew it was in scalar context. No term
or operator in scalar context will ever put a list on the stack.
Instead, it will put one scalar on the stack, whatever it feels like,
which is unlikely to be the last value of the list it
would have returned in list context, because the
last value is not likely to be the most useful value in scalar
context. Got that? (If not, you'd better reread this paragraph,
because it's important.)
Now back to true LIST
s, the
ones that do list context. Until now we've pretended that list
literals were just lists of literals. But just as a string literal
might interpolate other substrings, a list literal can interpolate
other sublists. Any expression that returns values may be used within
a list. The values so used may be either scalar values or list values,
but they all become part of the new list value because
LIST
s do automatic interpolation of
sublists. That is, when a LIST
is
evaluated, each element of the list is evaluated in a list context,
and the resulting list value is interpolated into
LIST
just as if each individual element
were a member of LIST
. Thus arrays lose
their identity in a LIST
.[18] The list:
(@stuff,@nonsense,funkshun())
contains the elements of @stuff
,
followed by the elements of @nonsense
, followed by
whatever values the subroutine &funkshun
decides to return when called in list context. Note that any or all of
these might have interpolated a null (empty) list, in which case it's
as if no array or function call had been interpolated at that point.
The null list itself is represented by the literal
()
. As with a null array, which interpolates as a
null list and is therefore effectively ignored, interpolating the null
list into another list has no effect. Thus,
((),(),())
is equivalent to
()
.
A corollary to this rule is that you may place an optional comma at the end of any list value. This makes it easy to come back later and add more elements after the last one:
@releases = ( "alpha", "beta", "gamma", );
Or you can do away with the commas entirely: another
way to specify a literal list is with the qw
(quote
words) syntax we mentioned earlier. This construct is equivalent to
splitting a single-quoted string on whitespace. For example:
@froots = qw( apple banana carambola coconut guava kumquat mandarin nectarine peach pear persimmon plum );
(Note that those parentheses are behaving as quote characters, not ordinary parentheses. We could just as easily have picked angle brackets or braces or slashes. But parens are pretty.)
A list value may also be subscripted like a normal array. You must put the list in parentheses (real ones) to avoid ambiguity. Though it's often used to fetch a single value out of a list, it's really a slice of the list, so the syntax is:
(LIST)[LIST]
Examples:
# Stat returns list value. $modification_time = (stat($file))[9]; # SYNTAX ERROR HERE. $modification_time = stat($file)[9]; # OOPS, FORGOT PARENS # Find a hex digit. $hexdigit = ('a','b','c','d','e','f')[$digit-10]; # A "reverse comma operator". return (pop(@foo),pop(@foo))[0]; # Get multiple values as a slice. ($day, $month, $year) = (localtime)[3,4,5];
A list may be assigned to only if each element of the list is itself legal to assign to:
($a, $b, $c) = (1, 2, 3); ($map{red}, $map{green}, $map{blue}) = (0xff0000, 0x00ff00, 0x0000ff);
You may assign to undef
in a list. This is
useful for throwing away some of the return values of a
function:
($dev, $ino, undef, undef, $uid, $gid) = stat($file);
The final list element may be an array or a hash:
($a, $b, @rest) = split; my ($a, $b, %rest) = @arg_list;
You can actually put an array or hash anywhere in the list you
assign to, but the first array or hash in the list will soak up all
the remaining values, and anything after it will be set to the
undefined value. This may be useful in a local
or
my
, where you probably want the arrays
initialized to be empty anyway.
You can even assign to the empty list:
() = funkshun();
That ends up calling your function in list context, but discarding the return values. If you had just called the function without an assignment, it would have instead been called in void context, which is a kind of scalar context, and might have caused the function to behave completely differently.
List assignment in scalar context returns the number of elements produced by the expression on the right side of the assignment:
$x = ( ($a, $b) = (7,7,7) ); # set $x to 3, not 2 $x = ( ($a, $b) = funk() ); # set $x to funk()'s return count $x = ( () = funk() ); # also set $x to funk()'s return count
This is handy when you want to do a list assignment in a
Boolean context, because most list functions return a null list when
finished, which when assigned produces a 0, which is interpreted as
false. Here's how you might use it in a while
statement:
while (($login, $password) = getpwent) { if (crypt($login, $password) eq $password) { print "$login has an insecure password! "; } }
You may find the number of elements in the array
@days
by evaluating @days
in a
scalar context, such as:
@days + 0; # implicitly force @days into a scalar context scalar(@days) # explicitly force @days into a scalar context
Note that this only works for arrays. It does not work for list values in general. As we mentioned earlier, a comma-separated list evaluated in scalar context returns the last value, like the C comma operator. But because you almost never actually need to know the length of a list in Perl, this is not a problem.
Closely related to the scalar evaluation of
@days
is $#days
. This will
return the subscript of the last element of the array, or one less
than the length, since there is (ordinarily) a 0th element.
Assigning to $#days
changes the length of the
array. Shortening an array by this method destroys intervening
values. You can gain some measure of efficiency by pre-extending an
array that is going to get big. (You can also extend an array by
assigning to an element beyond the end of the array.) You can
truncate an array down to nothing by assigning the null list
()
to it. The following two statements are
equivalent:
@whatever = (); $#whatever = -1;
And the following is always true:
scalar(@whatever) == $#whatever + 1;
Truncating an array does not recover its memory. You have to
undef(@whatever)
to free its memory back to your
process's memory pool. You probably can't free it all the way back
to your system's memory pool, because few operating systems support
this.