develooper 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


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