Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Context tutorial

by kyle (Abbot)
on Jan 23, 2009 at 19:20 UTC ( [id://738558] : perltutorial . print w/replies, xml ) 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.

# Example 1. # @now will be (40, 51, 20, 9, 0, 109, 5, 8, 0) @now = localtime(); # Example 2. # $now will be "Fri Jan 9 20:51:40 2009" $now = localtime();

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:

perl -e "@now = localtime(); for $now(@now) {print $now;}" 432351301092120 perl -e "$now = localtime(); print $now;" Tue Jan 13 05:26:30 2009

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.

# Example 3. # $sec will be 40, $min will be 51, $hr will be 20 ($sec,$min,$hr) = localtime();

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:

my ($x) = localtime(); # Example 4

To write it without the list context, drop the parentheses.

my $x = localtime(); # Example 5

Other common occurrences of context

When creating a hash, the elements are in list context. This probably doesn't do what's intended:

# BAD! [Example 6] my %h = ( now => localtime() );

Instead, localtime needs scalar to force it to be a single value associated with the key. There's more about scalar later in this tutorial.

# GOOD [Example 7] my %h = ( now => scalar localtime() );

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.

# GOOD [Example 8] my %h = ( now => [ localtime() ] );

If you're not familiar with references, see perlreftut, perlref, and References quick reference.

The arguments to a call to a user-defined sub are in list context also.

# Example 9 sub print_time { my $now = shift @_; print "The time is now $now\n"; } # prints "The time is now 40" print_time( localtime() ); # prints "The time is now Tue Jan 13 05:26:30 2009" print_time( scalar localtime() );

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.

# Example 10 my @loc = ($offset, $length); my $part = substr( $string, @loc );

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.

print clock(); # Example 11 sub clock { return localtime(); }

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:

print scalar localtime(); # Example 12

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.

my $match_count = ()= /x/g; # Example 13

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

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.

# Example 14 while (<>) { ponder( $_ ); # 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.

# Example 15 sub print_context { if ( wantarray() ) { print "list\n"; } elsif ( defined wantarray() ) { print "scalar\n"; } else { print "void\n"; } } print_context(); ()= print_context(); scalar print_context(); __END__ void list scalar

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.

# Example 16 my $beer_inventory = '99 bottles'; print "how much beer? $beer_inventory\n"; $beer_inventory--; # take one down... print "how much beer? $beer_inventory\n"; __END__ how much beer? 99 bottles how much beer? 98

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).

# Example 17 my $s = "12 monkeys"; my $n = 31337; my $stringified = ''. $n; # "31337" my $numified = 0+ $s; # 12 my $boolean = !! $n; # 1

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.

Context clash

A single value (such as a scalar) in a list context becomes a list with one item.

# Example 18 my $scaley = 'snake'; my @listy = $scaley; # does the same thing: #my @listy = ('snake');

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).

# Example 19 my @t = ( 'one', 'two' ); my $x = ( 'one', 'two' ); # 'two' my $y = @t[0,1]; # 'two' my $z = ( 'larry', 'moe', @t[0,1] ); # 'two' my $r = ( 'larry', 'moe', @t ); # 2 my $f = ( 'old', 'man', localtime() ); # "Fri Jan 9 20:51:40 2009"

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.

Interpolative 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.

# Example 20 my $friend = 'Perl'; my $literal = '$friend'; # literally, '$friend' my $expanded = "$friend"; # literally, 'Perl'

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).

More context

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.

Another good source of information about context is What is Scalar Context? by Dominus.

Thanks to belg4mit, tye, theorbtwo, Arunbear, bart, zentara, ikegami, Limbic~Region, Narveson, jdporter, moritz, Porculus, ww, gwadej, oshalla, and gwadej for commenting on an earlier draft!

Replies are listed 'Best First'.
Re: Context tutorial
by gwadej (Chaplain) on Jan 23, 2009 at 20:31 UTC

    The phrase

    on Linux or a derivative like newer Macs

    might be better said as

    on a Unix-like operating system (like Linux or newer Macs)

    I'm pretty sure the FreedBSD guys would not like being called a derivative of Linux.

    G. Wade

      Updated, thanks!

Re: Context tutorial
by merlyn (Sage) on Jan 24, 2009 at 01:39 UTC
Re: Context tutorial
by ikegami (Patriarch) on Jan 25, 2009 at 04:09 UTC

    To force a list context where there wouldn't be one otherwise, assign to an empty list.

    Then how come Example 4 is

    my ($x) = localtime(); # Example 4

    and not

    my $x = () = localtime();

    I've never see assigning to an empty list used to force a list context. Assigning to an empty list is used to count the number of elements in a list (which has nothing to do with context).

    In the case of badly written code, assigning to the empty list can differentiate between void and list context, but it never makes sense to use it to differentiate between scalar and list context as you show.

    To force list context, one adds parens around the LHS of the assignment or use a list slice.

    my ($x) = f(); # first element of list is assigned my $x = ( f() )[0]; # same, but overkill my $x = ( f() )[-1]; # last element of list is assigned my $x = ( f() )[0] # logical-or of the first elements || ( g() )[0]; # returned by f() and by g()

    Update: Added example.

      I've never see assigning to an empty list used to force a list context. Assigning to an empty list is used to count the number of elements in a list (which has nothing to do with context).

      It has to do with context. Assigning to the empty list forces list context upon the RHS. It returns the empty list in list context, and the number of elements of the RHS in scalar context. Consider:

      print my $x = ( 'a', 'b', 'c' ); # c print my @x = () = ( 'a', 'b', 'c' ); # nothing print my $x = () = ( 'a', 'b', 'c' ); # 3 print my $x = @a = ( 'a', 'b', 'c' ); # 3 print scalar ( 'a', 'b', 'c' ); # c print +() = ( 'a', 'b', 'c' ); # nothing print scalar ( () = ( 'a', 'b', 'c' ) ); # 3

      update: to make it clearer...

      sub bar { local $\; print "bar:"; print wantarray ? "list - " : "scalar - "; return ( "d", "e" ); } sub foo { local $\; print "foo:"; print wantarray ? "list - " : "scalar - "; return ( "c", bar ); } $\ = "\n"; print ( 'a', 'b', foo ); # adcde print scalar ( 'a', 'b', foo ); # e print +() = ( 'a', 'b', foo ); # nothing print scalar ( () = ( 'a', 'b', foo ) ); # 5 __END__ foo:list - bar:list - abcde foo:scalar - bar:scalar - e foo:list - bar:list - foo:list - bar:list - 5

        Assigning to the empty list forces list context upon the RHS.

        So does system, but you don't see me using system to force list context. Your code supports what I say:

        print ( 'a', 'b', foo ); # adcde print +() = ( 'a', 'b', foo ); # nothing

        Assigning to the empty list does more than force context. It's not a good choice to force list context.

Re: Context tutorial
by ww (Archbishop) on Jan 25, 2009 at 18:37 UTC
    With kudos regarding the content above -- and in a related context :-) -- readers of this thread may also find Context: compile-time vs. run-time, a follow-up thread, instructive and valuable.
Re: Context tutorial
by didess (Sexton) on Feb 02, 2009 at 23:44 UTC
    The way you print in the first example:

    perl -e "@now = localtime(); for $now(@now) {print $now;}"

    is tricky because the result looks rather like a scalar (a sort of big integer)

    and does not show the "list form" we got from the context. Something like :
    perl -e "@now = localtime(); print join(',',@now);"
    should give a better "image".

    More, unfortunately, the "scalar" output is a string of enumerated words

    which looks more like a list !

    (first impression is important for a tutor ;-)

Re: Context tutorial
by ig (Vicar) on Jan 24, 2009 at 19:53 UTC
    You can tell which kind of context an operator has by checking the standard Perl documentation. Every operator that creates a list context has "LIST" in its syntactic description.

    Where are these syntactic descriptions? I don't see them in perlop, where some of the descriptions are vague or silent on the issue of context in which operands are evaluated.

      They're in perlfunc.

      But I do think that that line in the tutorial should probably say

      Every operator that creates a list context for its operands ...
      just to be very clear.

      Between the mind which plans and the hands which build, there must be a mediator... and this mediator must be the heart.

        I've updated the tutorial. Thanks for your suggestion!

Re: Context tutorial
by parv (Parson) on Jul 10, 2009 at 11:50 UTC
    Argh, dang it! Just discovered the problem with substr & use of an array (reference) (get the substring from offset of 2 (to the end)). Of course, when I just add a useless wrapper, there is no problem since the arguments of offset & length are passed as scalars. Curses, poxes, and so on, so forth!
Re: Context tutorial
by Anonymous Monk on Sep 01, 2019 at 04:37 UTC
Re: Context tutorial
by toro (Beadle) on Jun 15, 2011 at 14:23 UTC
    I'm using Ubuntu Linux and double-quotes work for me.

    You're right jdporter, I have no idea what I did that made it seem like perl -e " ... " worked in that case.

    nodereaper, can you strike this? I guess that is not to form here.

    UPDATE: Aha. I found out what I did that worked. It wasn't exactly what was in the instructions and I don't know why it worked. I just learned about say and I've been using it everywhere.

    $ perl -E "@now = localtime(); for (@now) { say; }" 21 20 10 15 5 111 3 165 1

    A reply falls below the community's threshold of quality. You may see it by logging in.