Front page | perl.perl5.porters |
Postings from October 2016
Re: (\@a) = \($x,$y) in non-void context
Thread Previous
|
Thread Next
From:
Dave Mitchell
Date:
October 19, 2016 11:05
Subject:
Re: (\@a) = \($x,$y) in non-void context
Message ID:
20161019110528.GC3128@iabyn.com
On Wed, Oct 19, 2016 at 11:58:55AM +0200, Aristotle Pagaltzis wrote:
> * Dave Mitchell <davem@iabyn.com> [2016-10-19 10:24]:
> > There's one further issue I've noticed: undef on the LHS:
> >
> > sub inc { $_++ for @_ }
> >
> > inc($a, undef ); # "Modification of a read-only value attempted"
> > inc(($a, undef) = ($x, $y)); # increments $a and $y
>
> I think that’s correct.
>
> * David Nicol <davidnicol@gmail.com> [2016-10-19 11:00]:
> > Undef appears to be special in that it gets replaced with an alias to
> > the RHS element instead of throwing a compile-time error.
> >
> > $ perl -le '$x=$y=1; ($a,undef) = ($x,$y) ; print "a:$a x:$x y:$y"'
> > a:1 x:1 y:1
> > $ perl -le '$x=$y=1; ($a,2) = ($x,$y) ; print "a:$a x:$x y:$y"'
> > Can't modify constant item in list assignment at -e line 1, near ") ;"
> > Execution of -e aborted due to compilation errors.
>
> Correct that it’s special, but wrong guess as to why.
>
> sub x { join ":", \(@_) }
> my $lhs = x my($l1,$l2);
> my $rhs = x my($r2,$r2);
> my $ret = x(($l1,$l2)=($r1,$r2));
> say "lhs" if $lhs eq $ret;
> say "rhs" if $rhs eq $ret'
>
> This says “lhs”. It does not say “rhs” if you change the LHS of the
> assignment to (undef,undef) – which would be what it should say if such
> an assignment to undef were returning an alias to the RHS element.
No, you have a typo: my($r2,$r2) rather than $r1. With that changed, it
prints 'rhs' when changing ($l1,$l2) to (undef,undef).
Another clearer example would be:
sub x { $_++ for @_ }
my($l1,$l2,$r1,$r2) = (100,200,300,400);
my $ret = x((undef,undef)=($r1,$r2));
print "($l1,$l2) ($r1,$r2)\n";
which outputs:
(100,200) (301,401)
> * Dave Mitchell <davem@iabyn.com> [2016-10-19 10:24]:
> > I think that second call to inc should pass ($a, undef) rather than
> > ($a, $y) to inc, and should also die with "Modification of a read-only
> > value attempted".
>
> Apparently a literal `undef` on the LHS is special-cased to autovivify
> an anonymous scalar.
In fact, aassign replaces the undef with the RHS element.
> Which is a scalar that gets assigned to, which is what list assignment
> should return – so the current behaviour is correct.
I can see 4 ways this could be handled.
1. (...,undef,...) = (...) autovififies a new undefined scalar value then
assigns the RHS value to it, returning the new scalar;
2. it skips the assignment for that slot, and returns the RHS element;
3. it skips the assignment for that slot, and returns &PL_sv_undef (which
will croak if later modified);
4. it skips the assignment for that slot, and returns a fresh undef scalar.
(2) is the current behaviour. I'd like to change it to (3). (1) and (4)
seem inefficient, having to create a new mortal scalar.
I think (2) is definitely semantically incorrect: the essence of list
assignment is that it copies values: you shouldn't end up with aliases to
RHS elements.
--
You live and learn (although usually you just live).
Thread Previous
|
Thread Next