develooper Front page | perl.perl5.porters | Postings from October 2016

Re: (\@a) = \($x,$y) in non-void context

Thread Previous | Thread Next
From:
David Nicol
Date:
October 10, 2016 21:08
Subject:
Re: (\@a) = \($x,$y) in non-void context
Message ID:
CAFwScO8G6_-ivUhfjRBNR=7d7vCcZuSZGSQ3mu7gO-ECxkFMLA@mail.gmail.com
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.

TL;DR: SKIP TO BOTTOM



But is $a aliased to $c and $b aliased to $d? 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. Both cases should be
the same as

     \(@a) = \($a, $b);  \($a, $b) = \($c, $d);

should they 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? Does reference
aliasing only affect the symbol?

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 -- no, it's
an error, because undef is not "a reference to a datum of the right type"
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.

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).

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.

$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? That
is, does using an existing reference
as a l-value alter the referent or just the symbol?  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.

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. To make the example in the documentation work as described,
without undocumented side effects, l-value \(@array) must always start
by clearing @array.

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. Maybe using a refalias array construction
expression as an l-value should be a fatal error?

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.


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.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About