Skip Menu |
Report information
Id: 133064
Status: open
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: dp13 [at] sanger.ac.uk
Cc:
AdminCc:

Operating System: (no value)
PatchStatus: (no value)
Severity: low
Type: unknown
Perl Version: (no value)
Fixed In: (no value)



Subject: Multiple assignments in assignment ops
To: "perlbug [...] perl.org" <perlbug [...] perl.org>
From: Daniel Perrett <dp13 [...] sanger.ac.uk>
Date: Thu, 5 Apr 2018 16:17:41 +0000
Download (untitled) / with headers
text/plain 1.2k
The following are not equivalent, which I found surprising: $ perl -wle 'my $foo = {}; $foo->{b} = defined $foo->{b} ? $foo->{b} : scalar keys %$foo; print $foo->{b}' 0 $ perl -wle 'my $foo = {}; $foo->{b} //= scalar keys %$foo; print $foo->{b}' 1 Assignment operators other than '=' all appear to, in effect, assign the lvalue to undef first (if it does not exist); only then is the new value calculated... a bit like autovivification. This can be confirmed by jumping out of the operation before it completes: $ perl -wle 'my $foo = {}; for (1) { $foo->{b} += 1 + next; } print for keys %$foo' b This seems like one of those apparent 'bugs' for which there is a good and interesting reason... but I would have expected to find this behaviour made clear somewhere in the documentation on perlop or, failing that, perlref, and I cannot see it. Is it intentional? I tested on v5.18.2 v5.22.4 which I happened to have lying around at the time and did not find anything relevant in the major perldeltas since then. Daniel -- The Wellcome Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 1.3k
On Thu, 05 Apr 2018 09:48:30 -0700, dp13@sanger.ac.uk wrote: Show quoted text
> The following are not equivalent, which I found surprising: > > $ perl -wle 'my $foo = {}; $foo->{b} = defined $foo->{b} ? $foo->{b} : > scalar keys %$foo; print $foo->{b}' > 0 > > $ perl -wle 'my $foo = {}; $foo->{b} //= scalar keys %$foo; print > $foo->{b}' > 1 > > Assignment operators other than '=' all appear to, in effect, assign > the lvalue to undef first (if it does not exist); only then is the new > value calculated... a bit like autovivification. This can be confirmed > by jumping out of the operation before it completes: > > $ perl -wle 'my $foo = {}; for (1) { $foo->{b} += 1 + next; } print > for keys %$foo' > b > > This seems like one of those apparent 'bugs' for which there is a good > and interesting reason... but I would have expected to find this > behaviour made clear somewhere in the documentation on perlop or, > failing that, perlref, and I cannot see it. Is it intentional?
I don’t know offhand whether this is documented, but the difference is explained by the fact that regular assignment (=) evaluates the right-hand side first. (It has to work this way for common idioms like ‘local $x = $x’ to work.) Assignment versions of other operators, however, evaluate the lefthand side first. (In the case of //= &&= etc., it has to be this way, as the lhs determines whether the rhs is evaluated.) -- Father Chrysostomos
Date: Tue, 10 Apr 2018 10:49:26 -0500
To: Bram via RT <perlbug-followup [...] perl.org>
CC: Perl 5 Porters <perl5-porters [...] perl.org>
Subject: Re: [perl #133064] Multiple assignments in assignment ops
From: David Nicol <davidnicol [...] gmail.com>
Download (untitled) / with headers
text/plain 3.3k

It's clearly an unwanted autovivification bug, but can we call it an optimization? That is, an or-assign autovivs because it knows its going to need the l-value in a jiffy or two?

RHS evaluated first:
$  perl -le '$foo{x} = scalar keys %foo; print $foo{x}'
0

Container slot evaluated first, but as as r-value, does not autoviv
$  perl -le '$foo{x} or $foo{x} = scalar keys %foo; print $foo{x}'
0

assignment op accesses container slot only once, as l-value, which autovivs
$ perl -le '$foo{x} ||= scalar keys %foo; print $foo{x}'
1

even when it turns out the assignment isn't going to happen.
$  perl -le '$foo{x} &&= scalar keys %foo; print keys %foo'
x


The documentation
       Assignment operators work as in C.  That is,            $a += 2;        is equivalent to           $a = $a + 2;       although without duplicating any side effects that dereferencing the lvalue might trigger, such as from tie().  Other assignment operators work similarly. 

does imply that the LHS of an assignment op is going to get dereferenced as an lvalue, not an r-value and then as an lvalue, with the "although without duplicating" language there.

which gives us the "good and interesting reason" of "Assignment operators treat their left hand sides as l-values, which means autovivifying slots in containers."


It should be possible to adapt the crazy gymnastics Perl goes through to avoid autovivifying non-existent container slots when they are used in subroutine calls until their magical proxy l-value placeholders are actually assigned-to to the conditional assignment operators, but is it worth it and would it break things?




On Thu, Apr 5, 2018 at 7:36 PM, Father Chrysostomos via RT <perlbug-followup@perl.org> wrote:
Show quoted text
On Thu, 05 Apr 2018 09:48:30 -0700, dp13@sanger.ac.uk wrote:
> The following are not equivalent, which I found surprising:
>
> $ perl -wle 'my $foo = {}; $foo->{b} = defined $foo->{b} ? $foo->{b} :
> scalar keys %$foo; print $foo->{b}'
> 0
>
> $ perl -wle 'my $foo = {}; $foo->{b} //= scalar keys %$foo; print
> $foo->{b}'
> 1
>
> Assignment operators other than '=' all appear to, in effect, assign
> the lvalue to undef first (if it does not exist); only then is the new
> value calculated... a bit like autovivification. This can be confirmed
> by jumping out of the operation before it completes:
>
> $ perl -wle 'my $foo = {}; for (1) { $foo->{b} += 1 + next; } print
> for keys %$foo'
> b
>
> This seems like one of those apparent 'bugs' for which there is a good
> and interesting reason... but I would have expected to find this
> behaviour made clear somewhere in the documentation on perlop or,
> failing that, perlref, and I cannot see it. Is it intentional?

I don’t know offhand whether this is documented, but the difference is explained by the fact that regular assignment (=) evaluates the right-hand side first.  (It has to work this way for common idioms like ‘local $x = $x’ to work.)  Assignment versions of other operators, however, evaluate the lefthand side first.  (In the case of //= &&= etc., it has to be this way, as the lhs determines whether the rhs is evaluated.)

--

Father Chrysostomos


---
via perlbug:  queue: perl5 status: new
https://rt.perl.org/Ticket/Display.html?id=133064




--
“no man should be compelled to do what the laws do not require; nor to refrain from acts which the laws permit.” Calder v. Bull (U.S. 1798)
Date: Wed, 11 Apr 2018 08:34:44 +0100
Subject: Re: [perl #133064] Multiple assignments in assignment ops
CC: Bram via RT <perlbug-followup [...] perl.org>, Perl 5 Porters <perl5-porters [...] perl.org>
From: Dave Mitchell <davem [...] iabyn.com>
To: David Nicol <davidnicol [...] gmail.com>
Download (untitled) / with headers
text/plain 571b
On Tue, Apr 10, 2018 at 10:49:26AM -0500, David Nicol wrote: Show quoted text
> It should be possible to adapt the crazy gymnastics Perl goes through to > avoid autovivifying non-existent container slots when they are used in > subroutine calls until their magical proxy l-value placeholders are > actually assigned-to to the conditional assignment operators, but is it > worth it and would it break things?
No, it's not worth it. -- All wight. I will give you one more chance. This time, I want to hear no Wubens. No Weginalds. No Wudolf the wed-nosed weindeers. -- Life of Brian
To: Dave Mitchell <davem [...] iabyn.com>
Subject: Re: [perl #133064] Multiple assignments in assignment ops
CC: Bram via RT <perlbug-followup [...] perl.org>, Perl 5 Porters <perl5-porters [...] perl.org>
From: David Nicol <davidnicol [...] gmail.com>
Date: Wed, 11 Apr 2018 08:33:40 -0500
Download (untitled) / with headers
text/plain 1.4k
and if you really need it you can do it in Perl. "navdora" means non-autovivifying defined-or-assign. This was done with 5.22, which is after passing hash elements as subroutine arguments stopped autovivving them:

$ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora $foo{x},sub{scalar keys %foo}; print keys %foo,values%foo'
x0

$ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora($foo{x},sub{scalar keys %foo})=9; print keys %foo,values%foo'
x9


in practice it would surely make more sense to simply prefer a ternary over a //= rather than living with that ugly calling convention.



On Wed, Apr 11, 2018 at 2:34 AM, Dave Mitchell <davem@iabyn.com> wrote:
Show quoted text
On Tue, Apr 10, 2018 at 10:49:26AM -0500, David Nicol wrote:
> It should be possible to adapt the crazy gymnastics Perl goes through to
> avoid autovivifying non-existent container slots when they are used in
> subroutine calls until their magical proxy l-value placeholders are
> actually assigned-to to the conditional assignment operators, but is it
> worth it and would it break things?

No, it's not worth it.

--
All wight. I will give you one more chance. This time, I want to hear
no Wubens. No Weginalds. No Wudolf the wed-nosed weindeers.
    -- Life of Brian



--
“no man should be compelled to do what the laws do not require; nor to refrain from acts which the laws permit.” Calder v. Bull (U.S. 1798)
From: Daniel Perrett <dp13 [...] sanger.ac.uk>
Subject: RE: [perl #133064] Multiple assignments in assignment ops
To: "perlbug-followup [...] perl.org" <perlbug-followup [...] perl.org>
Date: Wed, 11 Apr 2018 13:41:27 +0000
Download (untitled) / with headers
text/plain 2.1k
FYI re //= Currently it sounds like if you squint at the docs hard enough it is implied. It might be a bug but not worth fixing. For context, Dave Mitchell does a lot of the hard work that someone needs to do deep in the bowels of perl. Daniel Show quoted text
-----Original Message----- From: David Nicol via RT [mailto:perlbug-followup@perl.org] Sent: 11 April 2018 14:34 To: Daniel Perrett Subject: Re: [perl #133064] Multiple assignments in assignment ops and if you really need it you can do it in Perl. "navdora" means non-autovivifying defined-or-assign. This was done with 5.22, which is after passing hash elements as subroutine arguments stopped autovivving them: $ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora $foo{x},sub{scalar keys %foo}; print keys %foo,values%foo' x0 $ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora($foo{x},sub{scalar keys %foo})=9; print keys %foo,values%foo' x9 in practice it would surely make more sense to simply prefer a ternary over a //= rather than living with that ugly calling convention. On Wed, Apr 11, 2018 at 2:34 AM, Dave Mitchell <davem@iabyn.com> wrote:
> On Tue, Apr 10, 2018 at 10:49:26AM -0500, David Nicol wrote:
> > It should be possible to adapt the crazy gymnastics Perl goes > > through to avoid autovivifying non-existent container slots when > > they are used in subroutine calls until their magical proxy l-value > > placeholders are actually assigned-to to the conditional assignment > > operators, but is it worth it and would it break things?
> > No, it's not worth it. > > -- > All wight. I will give you one more chance. This time, I want to hear > no Wubens. No Weginalds. No Wudolf the wed-nosed weindeers. > -- Life of Brian >
-- “no man should be compelled to do what the laws do not require; nor to refrain from acts which the laws permit.” Calder v. Bull (U.S. 1798) -- The Wellcome Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.
Date: Wed, 11 Apr 2018 13:44:18 +0000
Subject: RE: [perl #133064] Multiple assignments in assignment ops
From: Daniel Perrett <dp13 [...] sanger.ac.uk>
To: "perlbug-followup [...] perl.org" <perlbug-followup [...] perl.org>
Download (untitled) / with headers
text/plain 2.5k
Sorry, that was meant to be a forward to someone else and I pressed reply instead. Thanks all for looking at this. I am content for this bug to be closed, although the docs could definitely be clearer. I am willing to try writing something. Daniel Show quoted text
-----Original Message----- From: Daniel Perrett Sent: 11 April 2018 14:41 To: 'perlbug-followup@perl.org' Subject: RE: [perl #133064] Multiple assignments in assignment ops FYI re //= Currently it sounds like if you squint at the docs hard enough it is implied. It might be a bug but not worth fixing. For context, Dave Mitchell does a lot of the hard work that someone needs to do deep in the bowels of perl. Daniel
-----Original Message----- From: David Nicol via RT [mailto:perlbug-followup@perl.org] Sent: 11 April 2018 14:34 To: Daniel Perrett Subject: Re: [perl #133064] Multiple assignments in assignment ops and if you really need it you can do it in Perl. "navdora" means non-autovivifying defined-or-assign. This was done with 5.22, which is after passing hash elements as subroutine arguments stopped autovivving them: $ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora $foo{x},sub{scalar keys %foo}; print keys %foo,values%foo' x0 $ perl -le 'sub navdora($&):lvalue{defined$_[0]?$_[0]:$_[0]=&{$_[1]}};navdora($foo{x},sub{scalar keys %foo})=9; print keys %foo,values%foo' x9 in practice it would surely make more sense to simply prefer a ternary over a //= rather than living with that ugly calling convention. On Wed, Apr 11, 2018 at 2:34 AM, Dave Mitchell <davem@iabyn.com> wrote:
> On Tue, Apr 10, 2018 at 10:49:26AM -0500, David Nicol wrote:
> > It should be possible to adapt the crazy gymnastics Perl goes > > through to avoid autovivifying non-existent container slots when > > they are used in subroutine calls until their magical proxy l-value > > placeholders are actually assigned-to to the conditional assignment > > operators, but is it worth it and would it break things?
> > No, it's not worth it. > > -- > All wight. I will give you one more chance. This time, I want to hear > no Wubens. No Weginalds. No Wudolf the wed-nosed weindeers. > -- Life of Brian >
-- “no man should be compelled to do what the laws do not require; nor to refrain from acts which the laws permit.” Calder v. Bull (U.S. 1798) -- The Wellcome Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org