|Perl: the Markov chain saw|
Context tutorialby kyle (Abbot)
|on Jan 23, 2009 at 19:20 UTC||Need Help??|
"You will be miserable until you learn the difference between scalar and list context"
— Programming Perl 3rd ed, page 69
An introduction to context
Context is everywhere in Perl. Every operand is evaluated in some context. Every operator imposes a context to its operands. Every expression is constrained by the context in which it is evaluated.
The two main contexts are scalar context and list context. Another is void. An operator that works on scalars imposes a scalar context. You can tell which kind of context an operator has by checking the standard Perl documentation. Every operator that creates a list context for its operands has "LIST" in its syntactic description.
Context matters because operands in Perl can behave differently according to context. This is sort of like overloading. A function (or other expression) can provide different results depending on the context it's in.
Context in action
For these examples, I'll use localtime since it's a common function which evaluates differently according to context. In a list context, it returns a series of numeric values that describe the current time. In a scalar context, it returns a human readable string to describe the current time.
In example 1, we assign localtime to an array, which imposes a list context. The array takes in all the values returned by localtime.
In example 2, localtime is assigned to a scalar, which imposes a scalar context. In that context, localtime returns the string, "Fri Jan 9 20:51:40 2009".
You can try this yourself on the command line. If you're on a Windows box, you can run the code in Example 1 like this:
If you're on a Unix-like operating system (like Linux or newer Macs), replace the double quotes above with single quotes.
Now, back to context.
In example 3, localtime is assigned to a list expression which has three scalar variables in it (wrapped in parentheses). Because of the list expression, localtime() is in list context. The three variables get the first three values from the list that localtime() returns, and its other return values are discarded.
Note that this assignment is also to a list expression:
To write it without the list context, drop the parentheses.
Other common occurrences of context
When creating a hash, the elements are in list context. This probably doesn't do what's intended:
If you want to have the list returned from localtime in an array in the hash, an anonymous array reference is the best way to do that.
The arguments to a call to a user-defined sub are in list context also.
There is a way for a user-defined function to have its arguments in a scalar context, but that's seldom used, often discouraged, and outside the scope of this tutorial. Most of the time, subs' arguments are in list context.
Perl's built-ins don't follow this rule at all. Example 10 does not do what's intended.
Perl's substr takes only scalar arguments. Putting some of those arguments into an array this way won't work. (The above is equivalent to "substr( $string, 2 )" because @loc is in scalar context.)
Context propagates into sub calls
When control reaches a return, the operand to the right of that return finds itself in the context that the sub was in when it was called. That means that in the following code, localtime is in the list context from print.
A sub's calling context might come from some operator high up in the call stack.
Forcing scalar context
If you want to force a scalar context on an operand, use scalar. For example:
When you print, its operands are in list context. It accepts a list of values to be printed. If you just "print localtime()", it will print something like "40512090109580" (the list of values all stuck together), but "scalar localtime()" looks like "Fri Jan 9 20:51:40 2009".
Forcing list context
To force a list context where there wouldn't be one otherwise, assign to an empty list.
The "/x/g" in scalar context would match only once, but with the list context, it finds every match. The value of "()=" in scalar context is the number of items in the list.
Void context is a special case of scalar context. It's the context of something that doesn't have an operator working on it. The value of a thing in void context is discarded, not used for anything. For example, the body of a while loop is in void context.
The only way void context is like scalar context is that it's not list context. The only way void context is not like scalar context is that some things in void context can generate warnings that they wouldn't generate in a scalar context.
Determining context with wantarray
A sub can determine what context it was called in by using wantarray. If the sub is in list context, wantarray will return a true value. In scalar context, it returns a false value that's defined. In void context, it will return undef.
More flavors of scalars
The Camel book subdivides scalar context into numeric, string, and don't care context, but it's more useful to think of these as casts.
Scalar assignment is a "don't care" because numbers and strings are treated the same—passed through to the scalar variable to have and to hold just as they are. Another "don't care" cast is boolean because strings and numbers aren't converted when being interpreted as true or false. To learn more about how values are treated in boolean context, see True or False? A Quick Reference Guide
In numeric and string contexts, a variable might undergo a transformation from one to the other in order to facilitate the workings of the operator. In example 16, a string is cast to a number to accommodate the numeric operation of the postfix "--" operator.
To force an expression to a string, use "''." (that is, append to an empty string). To interpret an expression as a number, use "0+" (that is, add zero). It's better to use "0+" than some other identity function (such as "1*") because that's what overload uses to designate the numeric cast. To force a boolean interpretation, use "!!" (that is, boolean negation twice).
Every cast is possible. Strings can be cast to numbers or booleans. Numbers can be cast to strings or booleans. Booleans can be cast to numbers or strings.
A single value (such as a scalar) in a list context becomes a list with one item.
That's simple enough. What about the other way around? In scalar context, a list of expressions separated by commas evaluates to the whatever the last item evaluates to in scalar context. A slice of an array or hash in scalar context will similarly evaluate to the last element in the slice (for more on slices, see Slices).
Other things ordinarily used in list context have their own special scalar context behaviors. One particularly useful one is demonstrated by the $r value in example 19. An array in scalar context evaluates to the number of items in the array. For a list of others, see On Scalar Context.
This isn't a full fledged context like scalar and list context, but it helps to know in which places variables are expanded (interpolated) into their values. For a full list of these, see Quote and Quote-like Operators. For a brief example, see below.
To reiterate, this isn't a context the way "scalar context" is a context, and it isn't what we normally mean when we say simply "context." Still, it may help to think of it as a context when one is considering interpolation. For the full scoop including many other places this is relevant, see the full documentation (Quote and Quote-like Operators).
If the deep dark magic of wantarray leaves you wanting for more, look into Want and Contextual::Return, which are advertised to detect contexts I have not mentioned here. Also, look at overload for creating an object which can interpret itself differently in numeric and string contexts.