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:

  1. $string =~ /\d/g in list context yields all digit captures.

  2. () = ... is a list assignment to the empty list (assigns nothing, but evaluates the right-hand side in list context).

  3. $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

+=

$x = $x + $y

accumulate

-=

$x = $x - $y

subtract in place

*=

$x = $x * $y

scale

/=

$x = $x / $y

divide in place

%=

$x = $x % $y

modulo

**=

$x = $x ** $y

exponent in place

.=

$x = $x . $y

append (string)

x=

$x = $x x $y

repeat (string), or (@) x= n

&=

$x = $x & $y

bitmask AND-equals

|=

$x = $x | $y

bitmask OR-equals (set bits)

^=

$x = $x ^ $y

bitmask XOR-equals (toggle)

<<=

$x = $x << $y

shift-left in place

>>=

$x = $x >> $y

shift-right in place

&&=

$x = $x && $y

«narrow if currently true»

||=

$x = $x || $y

default if currently false

//=

$x = $x // $y

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, keys on 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 =).

See also#

  • Logical||=, //=, &&= are the workhorses of «default if missing» idioms.

  • Subscript — most lvalue forms involve a subscript.

  • Comma= parses out from the surrounding ,-list via precedence; understanding row 19 vs row 20 is what tells you when (a, b)=(c, d) distributes vs being a single list.