Clarify the rules for assigning/binding to multiple variables in a single declaration
The docs currently use "destructuring assignment" as a synonym for "list assignment". For example, in the Item and List assignment section, we provide these examples
my $f;
($f,) = 7,8,9; # list assignment to List with one element
say $f; # OUTPUT: «7»
say ( ($f,) ).VAR.^name; # OUTPUT: «List»
# ATTENTION: special declaration syntax!
my ($g) = 7,8,9; # list assignment to List with one element
say $g; # OUTPUT: «7»
say ( ($g) ).VAR.^name # OUTPUT: «List»
and then say that
The last two examples above are simple destructuring assignments that select the first item of the right-hand side list.
Conflating these two terms is understandable – as far as I can tell, most languages don't make this distinction (e.g., JavaScript calls both features destructuring assignment; PHP calls both features list assignment.
However, in Raku there is a distinction. As @jnthn pointed out in rakudo/rakudo/issues/4522:
At the heart of the issue is that the grammar parses a signature here; in the case we really do destructuring (
my (:$numerator, :$denominator) := 4.2) then the signature is exactly what we want. While "destructuring" is often used loosely to describe things likemy ($x, $y) = 1, 2, strictly this is an example of list assignment, not destructuring.The case given in the issue here is not destructuring either; there's no binding operator, and I think for attributes there cannot be. Rather, the situation here is that we are declaring a list of attributes, just as
my ($x, $y);is declaring a list of lexical variables. In this case, the signature should "decay" into just declarations (and in the case ofmy ($x, $y) = 1, 2, we expect it to also produce a list of the declared variables; what happens from there is also list assignment rather than destructuring).
Apparently this issue has been confusing people for a while – it came up in the 2017 Review of Perl 6 post:
I don’t understand the logic of making a syntactic distinction between list assignment and full destructuring assignment — and silently flattening the lefthand list structure in the first case — but there you have it.
And I'll admit that it's not a distinction I'd really focused on until it came up in the context of that Rakudo issue. I think I now understand the distinction and will prepare a PR – but I'll be especially looking for feedback on it to be sure I don't misstate anything.
As the change I just made to this issue's title implies, I no longer think that the heart of this issue relates to "destructuring assignment" – in fact, I've come around to the view that "destructuring assignment" isn't that clear of a term in Raku.
Instead, I think this is really about clarifying the rules for binding/rebinding variables (which are much more consistently enforced post rakudo/rakudo#4536) and then explaining the consequences those rules have when declaring multiple variables. I recently wrote up the rebinding rules (as I understand them) for a StackOverflow answer. Here's the key part:
The rules for rebinding are:
- Sigilless "variables" cannot be rebound (and can't be reassigned, so they aren't really "variables")
- Variables with a sigil generally can be rebound, subject to the exception below.
- If a sigiled variable is part of a Signature, then it cannot be rebound unless it is declared to be rebindable via the
is copyoris rwtraits.
- This applies to a function's Signature (thus
sub f($a) { $a := 42 }is illegal)- It also applies to Signatures that are destructured as part of variable declaration with
:=. E.g., inmy ($var1, $var2) := ('foo', 'bar'), the right-hand side is a Signature and thus$var1and$var2cannot be rebound.
Between that and the info in the rakudo/rakudo#4536 thread, I think we have all the info we need to clear this up in the docs. Now it's just a matter of one of us finding the time to actually do so!