http://qs1969.pair.com?node_id=1152601

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

Hello fellow monks. This is actually the first time I end up posting here, because until now, I always found my answer while writing my question, or just before clicking "create". You were all my rubber ducks :). But I can't understand this one.

On the version of perl I have here (strawberry v5.20), this code yields two warnings:

use strict; use warnings; use List::Util qw( min ); use Data::Dump qw( pp ); my (@_x, @_y); my @one = 1; my @two = 0.5; pp { one => $#one, two => $#two }; pp @one, @two; for my $_in (1..5) { push @_x, "$_in"; my $_out = 0; #pp "$#_x", "$#one", min $#_x, $#one; #pp "$#_y", "$#two", min $#_y, $#two; my $x_max = min $#_x, $#one; my $y_max = min $#_y, $#two; pp { x => $x_max, y => $y_max }; $_out += $one[$_] for 0..$x_max; $_out -= $two[$_] for 0..$y_max; push @_y, $_out; } pp { one => $#one, two => $#two }; pp @_y;
Use of uninitialized value in addition (+) at test.pl line 28
Use of uninitialized value in subtraction (-) at test.pl line 29
Unless I'm mistaken, this means I'm reaching for elements outside of @one and @two, even though $x_max and $y_max should not exceed the highest index.

I don't understand how with $#one == 0 and $x_max = min $#_x, $#one I find that $x_max > 0. What surprises me even more is that the warning disappears when I add the two commented lines (removing the quotes shows that min returns an alias and not a copy of the value).

Did I miss something obvious, or is this some weird side effect of my code?

Replies are listed 'Best First'.
Re: min $#a, $#b > $#b
by toolic (Bishop) on Jan 12, 2016 at 19:32 UTC
    More data to narrow your search of perldeltas... I get warnings on 5.22, but not with 5.14 and 5.16 (all on linux).

      Oh, thanks, I'm kind of surprised to learn that this is a "new" problem.

Re: min $#a, $#b > $#b
by Anonymous Monk on Jan 12, 2016 at 21:16 UTC

    Most likely a List::Util issue. When you replace the min definition with

    sub min { my ($a, $b) = @_; $a < $b ? $a : $b }
    it works correctly.

    Check the tracker if it's reported. I think it could be rt://107970. Perl $#arr is done with magic:

    $ perl -MDevel::Peek -e 'my @a = (); Dump $#a;'
    SV = PVMG(0x1034280) at 0xfe1cb8
      REFCNT = 1
      FLAGS = (GMG,SMG)
      IV = 0
      NV = 0
      PV = 0
      MAGIC = 0x1003260
        MG_VIRTUAL = &PL_vtbl_arylen
        MG_TYPE = PERL_MAGIC_arylen(#)
        MG_OBJ = 0x1000658
    

      Thanks, this does look like a probable cause.

      Perl $#arr is done with magic:

      Only when used as an lvalue.

      Workaround: 0+$#a.

Re: min $#a, $#b > $#b
by FreeBeerReekingMonk (Deacon) on Jan 12, 2016 at 19:42 UTC

    Whoops.. Eily caught me telling lies... ok, made a minimal working program:

    use List::Util qw( min ); my @A; for $_ (1..5) { push @A, $_; $max = min($#A, 0); $t = ref $#A; print "$max = min($#A,0)\n"; }

    Output:
    0 = min(0,0) 1 = min(1,0) 0 = min(2,0) 0 = min(3,0) 0 = min(4,0)

    YOU FOUND A BUG! workaround it like this: $max = min(0+$#A, 0);

      Adding scalar seems to fix it..
      use List::Util qw( min ); my @one = (1); for my $_in (1..5) { push @_x, "$_in"; my $x_max = min scalar($#_x), $#one; print "SET my \$x_max $x_max = min \$#_x $#_x, \$#one $#one;\n"; } SET my $x_max 0 = min $#_x 0, $#one 0; SET my $x_max 0 = min $#_x 1, $#one 0; SET my $x_max 0 = min $#_x 2, $#one 0; SET my $x_max 0 = min $#_x 3, $#one 0; SET my $x_max 0 = min $#_x 4, $#one 0;

      Though I don't quite understand why. Real bug perhaps?

        Actually anything that will initiate a new value instead of just forwarding the current one will work (like adding quotes around the variable, 0+$var, or even scalar($var), though I wasn't actually expecting this one), because the new value won't have the same magic. I did think about forcing a copy of some variables (which explains the quotes in some parts of my code), but since I had been working on the issue for a while (I started with much bigger code, I reduced it trying to find the bug), I wasn't sure at the time of my post whether I was doing some kind of silly mistake, and I never thought about forcing the copy on the parameters of min. Thanks for the answer !

        yup, real bug. happens in v5.20.2

      Don't ever wipe the original content of any node you've written, even if you've solved your problem; you're clarifying your issue; or you realize you just made a "D'oh!" Mark the changed/new content with the word "Update." Don't delete! Doing so is likely to make replies you've received unintelligble to future readers. Use <strike> ... </strike> if you must.
      -- How do I post a question effectively?

        understood.

      Actually @one in scalar context is the size of the array, $#one is the index of the last element, as shown by the data I print line 12