Front page | perl.perl5.porters |
Postings from October 2016
Re: (\@a) = \($x,$y) in non-void context
Thread Previous
From:
Aristotle Pagaltzis
Date:
October 11, 2016 06:20
Subject:
Re: (\@a) = \($x,$y) in non-void context
Message ID:
20161011062028.GA98564@plasmasturm.org
* David Nicol <davidnicol@gmail.com> [2016-10-10 23:12]:
> On Fri, Oct 7, 2016 at 10:39 AM, Father Chrysostomos <sprout@cpan.org> wrote:
> >
> > Dave Mitchell wrote:
> > > In the current implementation the first two cases are equivalent;
> > > however, in the last (lval) case they differ; with this:
> > >
> > > \(@a) = \($a, $b); \(@a) = \($c, $d);
> > >
> > > @a[0,1] are left aliased to $c and $d, as you'd expect; with this:
> > >
> > > (\(@a) = \($a, $b)) = \($c, $d);
> > >
> > > @a[0,1] are left aliased to $a and $b.
> >
> > I would consider that a bug.
>
> But is $a aliased to $c and $b aliased to $d?
Of course not.
> Because that is what it looks like should happen, in both cases, with
> @a, ($a,$b), and ($c,$d) now all referencing the same memory
> locations.
All of $a $b $c and $d only ever show up on a RHS. What makes you think
any of them should get aliased to any of the others?
> Both cases should be the same as
>
> \(@a) = \($a, $b); \($a, $b) = \($c, $d);
>
> should they not?
Absolutely not.
> Does
>
> (\$a = \$b) = \$c;
>
> not make all three of $a, $b and $c, as well as whatever $a was
> aliased to previously, if anything, equivalent?
Again, $b and $c only show up on the RHS. Why would they have been
rebound at any stage?
> Does reference aliasing only affect the symbol?
Yes, by definition. What else would it affect? `\$a = \$b` says “make
the name $a refer to the same scalar that the name $b refers to”.
> Looking at the current perlref.pod, it seems that in
>
>
> 855
> 856 Each element on the right-hand side must be a reference to a datum of the
> 857 right type. Parentheses immediately surrounding an array (and possibly
> 858 also C<my>/C<state>/C<our>/C<local>) will make each element of the array an
> 859 alias to the corresponding scalar referenced on the right-hand side:
> 860
> 861 \(@a) = \(@b); # @a and @b now have the same elements
> 862 \my(@a) = \(@b); # likewise
> 863 \(my @a) = \(@b); # likewise
> 864 push @a, 3; # but now @a has an extra element that @b lacks
> 865 \(@a) = (\$a, \$b, \$c); # @a now contains $a, $b, and $c
> 866
>
> line 865 neglects to mention that @b's first three elements have been
> aliased, also that @b[ 3 .. $#b ] have been clobbered somehow
I have no idea why you would think that. @b is not in affected in any
way any point of during the execution of this example.
In the example, @a and @b are completely separate and unrelated arrays.
The only relation they acquire is that any of the first 3 lines of the
example will cause the scalar stored at each index of @a to be an alias
to the scalar at the corresponding index of @b, just as if you had said
something like
\$a[$_] = \$b[$_] for 0 .. $#b;
Now if you do e.g. ++$a[0] then $b[0] will reflect that change because
it is the same scalar. But if you do `splice @a, 0, 1, 0` then $a[0] and
$b[0] will differ from then on, because you have changed what elements
@a contains, and the arrays themselves are unrelated.
> no, it's an error, because undef is not "a reference to a datum of the
> right type"
There is no undef on the RHS. There’s three scalar refs, and @a stores
scalars, so @a becomes an array containing three elements, each of which
is an alias for the scalar referenced by the ref at the corresponding
index of the RHS list.
> and also, the assignment to \3 -- aliasing is a persistent
> form of assignment -- should throw a fatal along the lines of "cannot
> make read-only value an alias."
>
> the ERRORS section in http://perl5.git.perl.org/perl.git/blob?f=t/op/lvref.t
> seems to indicate that the error should be
>
> "can't modify reference to read-only" --- but no, $a[-1] isn't an alias to 3,
> it's just a value, so modifying \$a[-1] should work. But it can only
> work by clobbering $a[-1]
> instead of aliasing \${3} or something like that.
OK, now I cannot even guess at the flaw in your mental model. I have no
idea where you imagine this \3 to come from. In any case it’s a mirage.
> IN CONCLUSION
>
> it seems that before Mitchell's question can be answered there has to be clarity
> about the semantics of writing to \(@non_empty_array).
Same as assignment. It clears the array, stores as many elements as
necessary to gobble up the remainder of the RHS, but unlike assignment,
each scalar is not a copy of the value on the RHS, but an alias to the
scalar referenced by the value on the RHS, which must be a scalar ref.
> Specifically, does aliasing scope the same way as writing? That is, after
>
> $original = "this is the original";
> \$alias = \$original;
> $alias = "new value overwrites old value";
>
> $original now has the new value, right? That's basic aliasing.
Correct.
> $second_original = "second old value";
> \$alias = $second_original;
>
> Here's the question -- does re-aliasing $alias affect only the alias
> symbol, or does $original get aliased to "second old value" too?
The former. Why would it be the latter? How would it be the latter?
> That is, does using an existing reference as a l-value alter the
> referent or just the symbol?
But all names are “an existing reference”. Every scalar variable name
is a name bound to a scalar. Aliasing rebinds it to another scalar. But
a scalar variable name is always bound to *some* scalar. There is no
qualitative difference between $original, $alias, and $second_original.
The only thing that refaliasing introduces is syntax that allows you to
rebind names, explicitly, at will, and including array and hash names.
Previously, it was only possible to rebind scalar variables, by using
foreach, and only for the duration for the scope in question.
(By going to CPAN for Array::RefElem you could rebind array and hash
elements as well, but hash or array name rebinding was not available
in any stable Perl-space interface.)
> Following the idiom of things like
>
> ($cipher_text = $plain_text) =~ y/0-9A-Za-z/a-ZA-Z0-9/;
>
> it would follow that the old referent is not involved at all when a
> reference is used as an l-value, aside from having its reference count
> decremented.
Precisely correct.
> The tricky thing though is that \(@array) is not about @array, it's
> rather about references to the elements. Except that the syntax is
> already being special cased as an exception to the rule that the RHS
> has to have the same number and type as the LHS, at least for empty
> @array.
The difference between @a vs (@a) in RHS context is deeply entrenched
in Perl 5: \@a is different from \(@a), and likewise for @a[0..9] vs
(@a)[0..9].
> To make the example in the documentation work as described, without
> undocumented side effects, l-value \(@array) must always start by
> clearing @array.
Which it already does.
> When l-value \(@arr) always starts by clearing @arr, the first
> assignment in
>
> (\(@a) = \($a, $b)) = \($c, $d);
>
> isn't going to do anything except gratuitous refcount adjustments or
> other internals exercising.
Correct.
> Maybe using a refalias array construction expression as an l-value
> should be a fatal error?
No. ($a=$b)=$c is not an error. Why should (\$a=\$b)=\$c be? It should
just do what one would reasonably expect.
> Or, expanded without the reference-to-list syntax, it should do whatever
>
> \(@a) = \($a, $b); \$a[0] = \$c; \$a[1] = \$d;
>
> does? I am currently understanding that \$a[1] as l-value has no
> effect on $b aside from decrementing a refcount.
Correct on all counts.
Or to retain the level of reference-to-list that you seem comfortable
with (given that you didn’t eschew it totally in your expansion) – it
should do the same as
\(@a) = \($a, $b); @a = (); \(@a) = \($c, $d);
which already works correctly. As does this, which is what it should
correspond to:
\(@a) = \($a, $b); \(@a) = \($c, $d);
much like ((@a) = ($a,$b)) = ($c,$d) expands in the same way.
> IN CONCLUSION OF THE CONCLUSION
>
> Your cheerful and often mistaken correspondent at this time
> recommends, for what it's worth, making syntactic reassignment to a
> reference expression a compile-time error, as the earlier assignments
> become no-ops, which surely can't be what the programmer was
> intending. And not just for array expressions.
>
> ( \$alias = $reference ) = $another_reference;
>
> should be a compile-time error too.
Again, ($a=$b)=$c is not an error, and there is no reason (\$a=\$b)=\$c
should be.
Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>
Thread Previous