Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

A list assignment gotcha

by jcb (Parson)
on Jul 30, 2020 at 02:01 UTC ( [id://11120043]=note: print w/replies, xml ) Need Help??


in reply to Not understanding 2 sentences in perldoc

There is one other surprise in here that I once found the hard way: plain assignment will operate on lists, but modifying assignments (+= in the example that I recall) will not — if you try to increment a group of values, only the last item in each list is affected.

Replies are listed 'Best First'.
Re: A list assignment gotcha (updated)
by AnomalousMonk (Archbishop) on Jul 30, 2020 at 03:38 UTC

    That's because the (scalar) operator of an op= imposes scalar context on the lists and so only the last element of each list is affected:

    c:\@Work\Perl\monks>perl -wMstrict -le "my ($x, $y, $z) = (30, 40, 50); ($x, $y, $z) += (3, 4, 5); print qq{$x, $y, $z}; " Useless use of a constant in void context at -e line 1. Useless use of a constant in void context at -e line 1. Useless use of private variable in void context at -e line 1. Useless use of private variable in void context at -e line 1. 30, 40, 55
    Raku can do these kinds of list operations; see Raku Programming/Meta Operators.

    Update: I'm not aware that you can do this with pure lists in Perl 5, but it can certainly be done with arrays:

    c:\@Work\Perl\monks>perl -wMstrict -le "my @ra = (30, 40, 50); my @rb = ( 3, 4, 5); ;; $ra[$_] += $rb[$_] for 0 .. $#ra; print qq{@ra}; " 33 44 55
    And via List::MoreUtils::pairwise():
    c:\@Work\Perl\monks>perl -wMstrict -le "use List::MoreUtils qw(pairwise); use vars qw($a $b); ;; my @ra = (30, 40, 50); my @rb = ( 3, 4, 5); ;; my @rc = pairwise { $a + $b } @ra, @rb; print qq{@rc}; " 33 44 55
    or
    c:\@Work\Perl\monks>perl -wMstrict -le "use List::MoreUtils qw(pairwise); use vars qw($a $b); ;; my @ra = (30, 40, 50); my @rb = ( 3, 4, 5); ;; pairwise { $a += $b } @ra, @rb; print qq{@ra}; " 33 44 55
    (The  use vars qw($a $b); statement quiets some warnings.)


    Give a man a fish:  <%-{-{-{-<

      Exactly — they look analogous, but they are not. The List::MoreUtils tricks are interesting, but actually wrap a loop iterating over arrays instead of being a true "vectorized" modifying assignment. There is probably something in PDL for this if your program does that kind of processing, but for a simple case with a list of Perl scalars, you need to use multiple statements.

        PDL is all about the "array programming", where you do an operation to the whole ndarray, and PDL just does that thing to everything in it. So for an ndarray, $pdl += 1 really would add 1 to all the elements in it.

        This is an example of the array-programming concept known these days as "broadcasting", which PDL used to slightly-confusingly call "threading".

Re: A list assignment gotcha
by LanX (Saint) on Jul 30, 2020 at 11:37 UTC
    > plain assignment will operate on lists, but modifying assignments (+= in the example that I recall) will not

    If you really needed this, it could be done with a little syntactic sugar

    something like

    L($x,$y,$z) += L(1,2,3);

    the trick would be to let L() ( for "list" ) return an object with overload ed operators (in scalar context) performing the side-effect

    Tho I'm not sure if the RHS needs to be packed into an object too, but I assume += is imposing scalar context.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      A bit trickier than I originally thought. What I didn't expect was the need to use the :lvalue on both the listifier and constructor.
      #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; { package L; use overload '+=' => sub { my ($self, $inc) = @_; $_ += shift @$inc for @$self; }; sub new :lvalue { bless $_[1], $_[0] } } sub L :lvalue { 'L'->new(\@_) } my ($x, $y, $z) = (10, 20, 30); L($x, $y, $z) += L(3, 2, 1); say "$x $y $z"; # 13 22 31
      You can use [3, 2, 1] on the RHS, as well.

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
        Hi

        > A bit trickier than I originally thought.

        I was about to update that one needs :lvalue and returning a tied scalar then.

        Surprised you made it without tie , my last use case must have been different than. :)

        update

        > You can use [3, 2, 1] on the RHS, as well.

        Nice! :)

        > on both the listifier and constructor.

        Genius!!! that's how you avoided using Tie::Scalar! :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11120043]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-20 00:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found