# 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 `=` ```perl 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: ```perl $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: ```perl 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: ```perl 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): ```perl $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 | ```perl $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](ternary.md)). - 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: ```perl ($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`. ```perl 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: ```perl 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](logical.md) — `||=`, `//=`, `&&=` are the workhorses of ”default if missing“ idioms. - [Subscript](subscript.md) — most lvalue forms involve a subscript. - [Comma](comma.md) — `=` 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.