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

I ran into something non-intutitive and boiled my code down to this. The script does slightly different things within the map statement when run with none, 1, or two args. With two args, the last input line is empty. In that case, a scalar $N is assigned an expression @a1..0 within the map statement. Why does this happen and how do I avoid the issue? Thanks.
#! /usr/bin/perl # perltest Demo of problem # Usage: # perltest # perltest 1 # perltest 1 2 $ARG1 = shift(); $ARG2 = shift(); open(F,$0); $c = 0; map { print "TRACE $_"; $c++; my @a = (1); my @b = @a[1..0]; if ( $ARG1 and $ARG2 ) { $N = @a[1..0]; } elsif ( $ARG1 ) { $N = @b; } } <F>; close(F); print "\nCOUNT = $c N = /$N/\n"; exit 0; #WATCH FOR THIS LINE!

Replies are listed 'Best First'.
Re: Assignment changes handle?
by CountOrlok (Friar) on Mar 04, 2005 at 19:28 UTC
    The following code mimics what is going:
    #!/usr/bin/perl use strict; use diagnostics; my @i = (5); my $n; map { $n = @i[1..0]; print $n.":"; my $u = "z"; } (6,2,3,4); print "outside:"; print $n;
    This prints "4:z:z:z:outside:z" I think it is a bug in the interpreter. There is no $i[1] so it ends up assigning the last element of the list passed to map or the last literal value ("z") from the stack.
    That's just my guess though.

      It can be even further reduced to:

      my @i; map { my $n = @i[()]; print "n=$n\n"; "z"; } 1 .. 4;

      Update: this outputs:

      $ perl test n=4 n=z n=z n=z

      Interestingly, it does not have the same behavior in non-void context:

      my @i; print map { my $n = @i[()]; print "n=$n\n"; "z"; } 1 .. 4;

      Update: this outputs:

      $ perl test n=4 n=4 n=4 n=4 zzzz
Re: Assignment changes handle?
by moot (Chaplain) on Mar 04, 2005 at 16:23 UTC
    How many elements are in an array slice from element 1 to element 0?
      1 .. 0 produces an empty list.
        Precisely.. which is why the OP is seeing $N set to 0.
Re: Assignment changes handle?
by ikegami (Patriarch) on Mar 04, 2005 at 17:04 UTC

    I can't tell what you want in $N, so here's some different things you can do:

    @a = (3, 4, 5); $N = @a[1..0]; # === $N = (); === $N = undef; $N = @a[0..1]; # === $N = (3, 4); === $N = 4; $N = () = @a[0..1]; # === $N = num of ele in (3, 4) === $N = 2; $N = [ @a[0..1] ]; # === $N = [3, 4]; === $N = ARRAY( +0x1abf0bc)

    You probably want to assign to an array:

    @N = @a[0..1]; # === @N = (3, 4);
Re: Assignment changes handle?
by osunderdog (Deacon) on Mar 04, 2005 at 17:34 UTC

    That's an odd one. I've reduced it down to the following:

    use strict; my $ARG1 = shift(); my $ARG2 = shift(); open(F,$0); my $N; map { print "TRACE $_"; my @a = (1); $N = @a[1..0]; #1; } <F>; close(F); print "\nN = /$N/\n"; #WATCH FOR THIS LINE!

    It appears as though $N is getting set to the return value from the map operation. Notice that I added a commented out line in the map block. If you uncomment this, the value of $N will always be 1.

    I don't know what the answer is, but I thought this was worth mentioning. Also, changing this to a while doesn't have this problem, so I think it definitely has something to do with the return value from the map function.

    HIH


    "Look, Shiny Things!" is not a better business strategy than compatibility and reuse.