The =
operator itself is always item assignment level, which is tighter than comma. However, it may apply a "sub-precedence", which is how it is compared to any further infixes in the expression that follow it. The term that was parsed prior to the =
is considered, and:
- In the case that the assignment is to a
Scalar
variable, then the =
operator works just like any other item assignment precedence operator, which is tighter than the precedence of ,
- In any other case, its precedence relative to following infixes is list prefix, which is looser than the precedence of
,
To consider some cases (first, where it doesn't impact anything):
$foo = 42; # $ sigil, so item assignment precedence after
@foo = 1; # @ sigil, so list assignment precedence after
@foo[0] = 1; # postcircumfix (indexing operator) means list assignment after...
$foo[0] = 1; # ...always, even in this case
If we have a single variable on the left and a list on the right, then:
@foo = 1, 2; # List assignment into @foo two values
$foo = 1, 2; # Assignment of 1 into $foo, 2 is dead code
These apply with the =
initializer (following a my $var
declaration). This means that:
loop (my $i = 0, my $j = $end; $i < $end; $i++, $j--) {
...
}
Will result in $i
being assigned 0
and $j
being assigned $end
.
Effectively, the rule means we get to have parentheses-free initialization of array and hash variables, while still having lists of scalar initializations work out as in the loop
case.
Turning to the examples in the question. First, this:
($a, $b) = test();
Parses a single term, then encounters the =
. The precedence when comparing any following infixes would be list prefix (looser than ,
). However, there are no more infixes here, so it doesn't really matter.
In this case:
sub test() { return 1, 2 }
my ($a, $b);
$a, $b = test();
The precedence parser sees the ,
infix, followed by the =
infix. The =
infix in itself is tighter than comma (item assignment precedence); the sub-precedence is only visible to infixes parsed after the =
(and there are none here).
Note that were it not this way, and the precedence shift applied to the expression as a whole, then:
loop (my $i = 0, my @lagged = Nil, |@values; $i < @values; $i++) {
...
}
Would end up grouped not as (my $i = 0), (my @lagged = Nil, |@values)
, but rather (my $i = 0, my @lagged) = Nil, |@values
, which is rather less useful.