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

Hi Monks,

I'm having trouble with the following code. I'm using __DATA__ for this, but originally ran into the problem with an external file. Basically, the act of reading from a handle seems to be nuking the content of my array of arrays, and I get a "use of uninitialized value..." once I've hit __DATA__.

Here's the code:

use strict; use warnings; my @testarray; push @testarray, [10,20],[30,40]; print "ok...\n"; print "$#testarray\n"; print "$testarray[0]->[0]\n\n"; foreach(@testarray){ while(<DATA>){ } } print "Nope...\n"; print "$#testarray\n"; print "$testarray[0]->[0]\n"; __DATA__ hello world

And here's the output:

ok... 1 10 Nope... 1 Use of uninitialized value in concatenation (.) or string at test_02.p +l line 17, <DATA> line 2.
map{$a=1-$_/10;map{$d=$a;$e=$b=$_/20-2;map{($d,$e)=(2*$d*$e+$a,$e**2 -$d**2+$b);$c=$d**2+$e**2>4?$d=8:_}1..50;print$c}0..59;print$/}0..20
Tom Melly, pm (at) cursingmaggot (stop) co (stop) uk

Replies are listed 'Best First'.
Re: Arrays and Handles Problem (updated)
by haukex (Archbishop) on May 02, 2019 at 11:57 UTC

    To give a little more information in addition to holli's answer: foreach (@testarray) loops over the array and assigns each element to $_, plus that iterator variable $_ is an alias to each original element of the array (see Foreach Loops), meaning that assigning to $_ changes the value in the original array. while (<DATA>) is actually while (defined($_ = readline DATA)) (I/O Operators), i.e. it is assigning to the same $_ variable.

    If you use an explicit loop variable in the foreach, e.g. foreach my $elem (@testarray), the problem goes away, and you can also do the same in the while, e.g. while ( my $line = <DATA> ).

    Update: Here you can see @testarray getting clobbered. The undef comes from the fact that <DATA> returns undef when it hits EOF (end of file).

    use warnings; use strict; use Data::Dump; my @testarray = ([10,20],[30,40]); dd "A", @testarray; foreach (@testarray) { dd "B", @testarray; while ( <DATA> ) { dd "C", @testarray; } dd "D", @testarray; } dd "E", @testarray; __DATA__ hello world

    Output:

    ("A", [10, 20], [30, 40]) ("B", [10, 20], [30, 40]) ("C", "hello\n", [30, 40]) ("C", "world\n", [30, 40]) ("D", undef, [30, 40]) ("B", undef, [30, 40]) ("D", undef, undef) ("E", undef, undef)
Re: Arrays and Handles Problem
by holli (Abbot) on May 02, 2019 at 11:52 UTC
    Well, you're using $_ as the loop variable in two nested loops. That's bound to cause trouble. Use an explicit loop variable in at least one of the loops and the problem should go away.

    Also, why the nested loop in the first place? Normally it makes no sense to read everything from DATA more than once.


    holli

    You can lead your users to water, but alas, you cannot drown them.

      Yes, __DATA__ is a bit of a red herring, since originally it was multiple reads of an external text file.

      That aside, thanks all for the explanation (and the fix). I must admit I thought I'd tried the solution already, but obviously not... also, I thought it was okay to use multiple nested instances of $_, and that each was local to its block, but clearly not...

      map{$a=1-$_/10;map{$d=$a;$e=$b=$_/20-2;map{($d,$e)=(2*$d*$e+$a,$e**2 -$d**2+$b);$c=$d**2+$e**2>4?$d=8:_}1..50;print$c}0..59;print$/}0..20
      Tom Melly, pm (at) cursingmaggot (stop) co (stop) uk
        I thought it was okay to use multiple nested instances of $_, and that each was local to its block, but clearly not...

        That's true for foreach, but not while (<>):

        use warnings; use strict; use Data::Dump; $_ = "foo"; for ("x","y") { dd $_; } dd $_; while (<DATA>) { dd $_; } dd $_; __DATA__ hello

        Output:

        "x" "y" "foo" "hello\n" undef