Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW

Mini-Tutorial: Scalar vs List Assignment Operator

by ikegami (Patriarch)
on Aug 20, 2009 at 16:05 UTC ( [id://790129]=perlmeditation: print w/replies, xml ) Need Help??

The symbol = is compiled into one of two assignment operators:

  • A list assignment operator is used if the left-hand side (LHS) of a = is some kind of aggregate.
  • A scalar assignment operator is used otherwise.

The following are considered to be aggregates:

  • Any expression in parentheses (e.g. (...))
  • An array (e.g. @array)
  • An array slice (e.g. @array[...])
  • A hash (e.g. %hash)
  • A hash slice (e.g. @hash{...})
  • Any of the above preceded by my, our or local

There are two differences between the operators.

Context of Operands

The two operators differ in the context in which their operands are evaluated.

  • The scalar assignment evaluates both of its operands in scalar context.
  • The list assignment evaluates both of its operands in list context.

Value(s) Returned

The two operators differ in what they return.

ReturnsContext in which Assignment Operator is Evaluated
Operatorscalar assignmentThe LHS as an lvalueThe LHS as an lvalue
list assignmentThe number of scalars returned by the RHSThe scalars returned by the LHS as lvalues

Note that the right-hand side is used for the list assignment in scalar context.


ExamplesContext in which Assignment Operator is Evaluated
Operatorscalar assignment
# @array evaluated in scalar context. my $count = @array;
# The s/// operates on $copy. (my $copy = $str) =~ s/\\/\\\\/g;
# Prints $x. print($x = $y);
list assignment
# @array evaluated in list context. my @copy = @array;
# @array evaluated in list context. my ($first) = @array;
# Only dies if f() returns an empty list. # This does not die if f() returns a # false scalar like zero or undef. my ($x) = f() or die;
my $count = () = f();
# Prints @x. print(@x = @y);

Related topics:

Update: Added examples.
Update: Incorporated JavaFan's additions.
Update: Removed list slices and mentioned state.
Update: One of the examples in the scalar context column did not depend on context. It has been moved to its own column. Also, added short explanations of examples.
Update: Reworded to not say there are only two assignment operators, because += and such are also assignment operators.
Update: Reworded to include new fangled []->@* to the list of aggregates.

Replies are listed 'Best First'.
Re: Mini-Tutorial: Scalar vs List Assignment Operator
by JavaFan (Canon) on Aug 20, 2009 at 16:39 UTC
    Beside my (...) there are also our (...) and local (...) that generate list context. sub (...) with sub an lvalue subroutine doesn't generate list context.

      Thanks. Fixed.

      Yes, there's nothing special about lvalue subs. f() doesn't cause the list assignment operator to be used, but (f()) does.

      $ perl -wle'sub f :lvalue { $x,$y } f()=(4,5); print $x,$y' Useless use of a constant in void context at -e line 1. Use of uninitialized value in print at -e line 1. 5 $ perl -wle'sub f :lvalue { $x,$y } (f())=(4,5); print $x,$y' 45
Re: Mini-Tutorial: Scalar vs List Assignment Operator
by dec (Beadle) on Aug 21, 2009 at 00:48 UTC
    You should maybe look up the wantarray documentation, since it seems it could be very relevant here. In case you don't know, it lets a function determine what context it has been called in (list, scalar or void). Handy when you want to be able to respond differently to different calling contexts ... or even just raise an error/warning when called with the wrong context, eg:
    sub pedantic_syswrite { my $context=wantarray; if (defined ($context)) { if ($context) { # caller wants an array, which is (mostly) silly f +or write die "write doesn't return an array, silly!\n"; } else { # scalar context # no warning, because user should always check return value syswrite @_; } } else { # void context die "I'm not going to write if you don't check my return value\n"; } }
    So, ok, maybe the code shouldn't die when called in a list context :-/ But it demonstrates how you might use it.

      I disagree with your strategy of preventing a function that returns a scalar from being called in list context. It limits options without adding benefits. (The other way around makes some sense.) But deciding what to have a sub return is a lengthy topic entirely unrelated to the behaviour of the assignment operators. Discussions specifically touching on the appropriateness of using wantarray have surfaced before, once not too long ago. Your thoughts would be better suited in that conversation or in a new conversation.

      Also note that our Tutorials section has a tutorial on context.

      By the way, syswrite(@_) doesn't work. Due to syswrite's prototype, the call is equivalent to syswrite(scalar(@_)) and results in a compilation error. You need something like:

      if (@_ == 2) { syswrite($_[0], $_[1] ) } elsif (@_ == 3) { syswrite($_[0], $_[1], $_[2] ) } elsif (@_ == 4) { syswrite($_[0], $_[1], $_[2], $_[3]) } else { die }
        On "preventing a function that returns a scalar from being called in list context".. yes, I agree. I did say that it probably wasn't a good idea. The idea was just to show how to use wantarray: ie, how to test the various return values.

        I had a suspicion as well when I wrote the code that the syswrite wasn't correct. Thanks for pointing it out.

        With all that was wrong with my post, don't I at least get some credit for suggesting that programmers should test the return value of syswrite instead of assuming it works? Besides flagging that wantarray could be useful here (if only so the programmer has a way to test directly whether a particular construct implies a list or array context) that's the other point I was trying to make.

Re: Mini-Tutorial: Scalar vs List Assignment Operator
by biohisham (Priest) on Aug 22, 2009 at 14:23 UTC
    one of the frequently used functions are map and grep, both with a similar syntax and arguments but BLOCK and EXPR in a grep statement are evaluated in a scalar context while in a map statement they are evaluated in a list context, it would be really great if you could address the evaluation differences as you've the assignment one. I don't really know much about the inner working of both functions because I am not as much experienced but I am puzzled by the way list and scalar contexts are presented.

    Thanks A lot.

    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.

      The purpose of grep is to filter a list. It does so by evaluating a piece of code for each item in the argument list. It wants a yes/no answer from the code it executes, so scalar context is warranted.

      The purpose of map is to transform a list. There is no correlation between in the size of the input list and the size of the output list. A given element may be transformed into zero, one or many elements, so list context is warranted.

      To tie this back to the subject at hand, this is basically how all operators work:

      • If an operator requires exactly one value for an operand (such as either operand of the scalar assignment operator), the operator will impose a scalar context on that operand.
      • If an operator requires multiple values for an operand (such as either operand of the list assignment operator), the operator will impose a list context on that operand.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://790129]
Front-paged by Arunbear
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-04-15 03:36 GMT
Find Nodes?
    Voting Booth?

    No recent polls found