http://www.perlmonks.org?node_id=314681

liz has asked for the wisdom of the Perl Monks concerning the following question:

Aristotle's answer to Switching on internal UTF-8 flaq on DBI result from database made me find the following phenomenon:
$a = [[0]]; foreach (@$a) { $_++ foreach @$_ } print $a->[0][0],$/; $_++ for map @$_, @{$a}; print $a->[0][0],$/; __END__ 1 1
The expected output is:
1 2
The strange thing is that the extra list flattening with map() doesn't work. I don't see any reason why it shouldn't. I guess the question is: is this a bug or not?

Liz

Update:
Not a bug, just copying of the list with map(). Thanks to !1, blokhead and holo for the enlightenment.

Replies are listed 'Best First'.
Re: $_ and list flattening with map()
by !1 (Hermit) on Dec 14, 2003 at 21:18 UTC

    I always thought map just returns copies of the values?

    my @a = qw(1 2); my @b = \(@a); my @c = \(map $_,@a); print "Addresses do not match$/" unless "@b" eq "@c"; __END__ Addresses do not match

    Of course, changing your map to:

    ${$_}++ for map \(@$_),@{$a};

    Will make it work as expected.

Re: $_ and list flattening with map()
by blokhead (Monsignor) on Dec 14, 2003 at 21:23 UTC
    $_++ for map @$_, @{$a};
    The difference is that you do the increment outside of the scope in which map aliases $_. This foreach is iterating over the return value of map, which is a list of copies (not aliases back into @$a). foreach now aliases $_ to this anonymous list of copies, so your modifications to $_ are lost.

    If you use map as a control structure (making it more of a direct translation of the first example), and do the increment inside map's block, you'll get what you expected originally:

    map { map { $_++ } @$_ } @$a;

    blokhead

Re: $_ and list flattening with map()
by holo (Monk) on Dec 14, 2003 at 21:44 UTC

    The line:

    $_++ for map $_, @a;

    generates an anonymous list with map, then iterates through it with for incrementing all its values. Once for is done, the list is thrown away (expensive no-op).

    The line:

    $_++ for my @b = map $_, @a;

    generates a list with map and throws it in @b, then iterates through it with for incrementing all values as before. This time, the list is not anonymous and may be accessed by using @b and it's not thrown away. Once map is evaluated, values in @b are totaly independent from values in @a.

Re: $_ and list flattening with map()
by pg (Canon) on Dec 14, 2003 at 22:05 UTC

    This tells why:

    use strict; use warnings; use Data::Dumper; my $a = [[0,1,2], [10,11,12]]; print \$a->[0][0], "\n"; print \$a->[0][1], "\n"; print \$a->[0][2], "\n"; print \$a->[1][0], "\n"; print \$a->[1][1], "\n"; print \$a->[1][2], "\n"; print "=======\n"; print \$_, "\n" for map @$_, @{$a};#one of your way print "=======\n"; foreach (@$a) { print \$_, "\n" foreach @$_ }#your other way

    Result, see how the 3rd set is the same as the 1st one, but the 2nd set stands alone:

    SCALAR(0x15551a4) SCALAR(0x15551b0) SCALAR(0x15551c8) SCALAR(0x155abd4) SCALAR(0x155500c) SCALAR(0x1571284) ======= SCALAR(0x15712c0) SCALAR(0x1571290) SCALAR(0x15551d4) SCALAR(0x15712e4) SCALAR(0x15712d8) SCALAR(0x15712cc) ======= SCALAR(0x15551a4) SCALAR(0x15551b0) SCALAR(0x15551c8) SCALAR(0x155abd4) SCALAR(0x155500c) SCALAR(0x1571284)