Assignment operators#
Plain assignment plus the compound forms — every binary operator that produces a value also has a compound assignment form that applies the operation in place.
Plain =#
my $x = 10; # scalar assignment
my @a = (1, 2, 3); # list assignment
my ($x, $y, $z) = (1, 2, 3); # destructuring
my ($first, @rest) = @items; # one + remainder
my %h = (a => 1, b => 2); # hash from key-value list
Assignment is right-associative — chains are evaluated right-to-left:
$a = $b = $c = 0; # parses as $a = ($b = ($c = 0))
# all three become 0
The whole assignment expression has a value: in scalar context it is the value assigned; in list context it is the list of elements assigned to, in left-to-right order:
my $count = (my @items = qw(a b c)); # $count = 3
# — number of elements assigned
# to @items, in scalar context
while ((my $line = <$fh>) ne '') { ... } # uses the assignment as
# both side-effect and value
List assignment in scalar context#
Probably the most-used Perl idiom that nobody can quote the rule for:
my $n = () = $string =~ /\d/g; # count digits in $string
Decoded:
$string =~ /\d/gin list context yields all digit captures.() = ...is a list assignment to the empty list (assigns nothing, but evaluates the right-hand side in list context).$n = (...)puts the list assignment in scalar context, which evaluates to the number of elements on the right.
Result: $n is the count of matches. There is no scalar(grep ...) or count built-in for this; the empty-list trick is the canonical idiom.
Compound assignment#
Every binary operator that fits the pattern OP= exists. The mechanics are identical to $x = $x OP $y, except that $x is evaluated only once on the left — which matters when the lvalue has a side-effect (e.g. an autoviv, a function call):
$h->{counter}++; # autoviv $h->{counter}, increment
$h->{counter} += 1; # same effect, but spell out the OP
Operator | Equivalent | Use |
|---|---|---|
|
| accumulate |
|
| subtract in place |
|
| scale |
|
| divide in place |
|
| modulo |
|
| exponent in place |
|
| append (string) |
|
| repeat (string), or |
|
| bitmask AND-equals |
|
| bitmask OR-equals (set bits) |
|
| bitmask XOR-equals (toggle) |
|
| shift-left in place |
|
| shift-right in place |
|
| «narrow if currently true» |
|
| default if currently false |
|
| default if currently undef |
$count += 5; # arithmetic
$path .= "/user"; # string append
$flags |= FLAG_VERBOSE; # set a flag bit
$flags &= ~FLAG_VERBOSE; # clear a flag bit
$cache ||= load_data(); # lazy populate
$cfg{key} //= $default; # default that respects 0 and ""
$str x= 3; # repeat in place
Lvalues — what can appear on the left#
The left operand of = (or any compound form) must be an lvalue — a location that can be written to. Perl’s lvalues include:
A simple scalar variable:
$x,$obj->{field}.An array or hash variable:
@arr,%h.An array element or slice:
$arr[3],@arr[1..3].A hash element or slice:
$h{key},@h{qw(a b c)}.A dereferenced container:
$$ref,@$aref,%{$h}.The
local-/my-declared form of any of the above.A substring:
substr($s, $offset, $len) = "...".A ternary whose branches are lvalues (see ternary).
The pseudo-operators
pos,vec,keyson tied hashes, certain@_slots, and a handful of specialised forms.
Most of the time you write an lvalue without thinking. The cases where you stop and check are exotic — substr as lvalue, a ternary as lvalue, an array slice as the target of a list assignment.
Multiple-target list assignment#
The right-hand side is evaluated first in list context, then distributed across the lvalues on the left. This makes swap easy:
($a, $b) = ($b, $a); # swap
($x, $y, $z) = ($y, $z, $x); # rotate left
If the lists differ in length:
More values on the right than slots on the left → extras silently discarded.
More slots on the left than values on the right → unfilled slots become
undef.
my ($a, $b) = (1, 2, 3, 4); # $a=1, $b=2; 3 and 4 dropped
my ($a, $b, $c) = (1, 2); # $a=1, $b=2, $c=undef
A trailing array or hash on the left slurps the remainder:
my ($head, @tail) = @items; # $head = first element
# @tail = the rest
my ($head, %tail) = @items; # if @items has key/value pairs
# after the first
Only one array or hash on the left side; otherwise it would not be unambiguous where one ends and the next begins.
Precedence#
Assignment operators sit at row 19 — quite low, looser than comparison and ?:, tighter only than the comma operators and the word-form logicals (and, or, not, xor). This is why my $fh = open ... or die works (or is even looser than =).