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.
Returns | Context in which Assignment Operator is Evaluated |
scalar | list |
Operator | scalar assignment | The LHS as an lvalue | The LHS as an lvalue |
list assignment | The number of scalars returned by the RHS | The scalars returned by the LHS as lvalues |
Note that the right-hand side is used for the list assignment in scalar context.
Examples
Examples | | Context in which Assignment Operator is Evaluated |
scalar | list |
Operator | scalar 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.
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. | [reply] [d/l] [select] |
|
$ 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
| [reply] [d/l] [select] |
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. | [reply] [d/l] |
|
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 }
| [reply] [d/l] [select] |
|
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.
| [reply] |
|
|
|
|
Re: Mini-Tutorial: Scalar vs List Assignment Operator
by biohisham (Priest) on Aug 22, 2009 at 14:23 UTC
|
| [reply] [d/l] |
|
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.
| [reply] [d/l] [select] |
|
|