Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Scope when initializing with references in a loop

by IraTarball (Monk)
on Dec 06, 2001 at 02:51 UTC ( #129783=perlquestion: print w/replies, xml ) Need Help??

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

Greetings bretheren and sisteren,

I was just sitting there, writing some Perl, when I was slapped by confussion. I have this array, I'll call it

my @array = ();
which I want to build into a linked list sort of structure. For the sake of a simple posting I'll make it more of a linked shrub like this.
$array[1] = { val => "The initial value for 1", one => 'undef' }; $array[0] = { val => "The initial value for 0", one => \$array[1]{val} + }; $array[2] = { val => "The initial value for 2", one => \$array[1]{val} + }; $array[3] = { val => "The initial value for 3", one => \$array[1]{val} + };
So that all of the links just point to the '1' element of my array. This seems to work the way I wanted. If I print it out with this code
for my $i (0 .. 3) { print "# $array[$i]{one}\n"; if (ref $array[$i]{one} eq 'SCALAR') { print "#\t${$array[$i]{one}}\n"; } }
I get
# SCALAR(0x8114938) # The initial value for 1 # undef # SCALAR(0x8114938) # The initial value for 1 # SCALAR(0x8114938) # The initial value for 1
So all the references have the same address and value. Great.
But no one would initialize an array like this, so I do it in a loop
for my $i (0 .. 3) { $array[$i] = { val => rand(time)%3, one => \$array[1]{val} }; }
D'oh! Now things seem to be broken. The same section of code for printing
print "\n"; for my $i (0 .. 3) { print "# $array[$i]{one}\n"; if (ref $array[$i]{one} eq 'SCALAR') { print "# \t${$array[$i]{one}}\n"; } }
gives me the irritating output of
# SCALAR(0x8114938) # The initial value for 1 # SCALAR(0x8114938) # The initial value for 1 # SCALAR(0x81adcd8) # 0 # SCALAR(0x81adcd8) # 0
Notice that the references have changed after reseting the value for @array[ 1 ]. So now $array[ 0 ]{one} points to the old value and the last 2 elements of the array point to the new value. The whole idea here was to have a reference to the value of $array[ 1 ]{val} so that other nodes would always have the current value, but that's broken.

What is happening here?

I suspect that this has to do with scoping inside the loop's block and that I'm creating something like a closure. Can anyone confirm or deny this?

I don't have any great project hanging on this, in fact I have a working version thanks to merlyn's node on using push for this, but it's bugging me that I don't understand why this doesn't work.

Thanks for your time,
Peter C.,

"It's not the fact that I have the monkeys that gives me the power, it's that I'll turn the monkeys loose that gives me the power."
~Kids in the Hall

Replies are listed 'Best First'.
Re: Scope when initializing with references in a loop
by IraTarball (Monk) on Dec 06, 2001 at 04:08 UTC
    BING
    The light bulb just went on.

    So in the loop I'm assigning an anonymous hash reference. If I change those lines to index to the actual element it behaves like I originally expected.

    $array[$i]{val} = rand(time)%3; $array[$i]{one} = \$array[1]{val};
    In the original code the anonymous hash is really a new hash, ofcourse, so it's a whole new chunk of data in the array element with a new memory location and everything. But the old data still had references to it from the first two elements of the array so it was not cleared, just no longer available from $array[1]{val}.

    I appologize for wasting space here, I think I just needed to throw this out there to get my head working.

    Thanks for your time,
    Peter C.,

Re: Scope when initializing with references in a loop
by George_Sherston (Vicar) on Dec 06, 2001 at 03:37 UTC
    I confess I don't understand the context for this question (i.e. *why* one wd do this) so I may be barking up the wrong tree, but the snag I see is that the first couple of times round the loop $array[1] is undefined.

    This:
    $array[0] = { val => "value number 0", one => 'undef' }; for my $i (1 .. 3) { $array[$i] = { val => rand(time)%3, one => \$array[0]{val} }; }
    Produces this:
    # undef # SCALAR(0x176f1c4) # value number 0 # SCALAR(0x176f1c4) # value number 0 # SCALAR(0x176f1c4) # value number 0
    ... which seems to be a bit more like what you wanted. But I'd love to know why you wanted it!

    George Sherston
      *why* one wd do this)
      It might be hard to see with this example, but the actual code has 'nodes' defined, each with references to it's "neighbors". The reference seemed clean because I could get at the values I want without having to figure out what the indices are for all of my neighbors. For this array it may seem trivial, but imagine an array of n dimensions.

      the snag I see is that the first couple of times round the loop $array[1] is undefined.
      This doesn't seem to matter. I was carefull to post the code in a way that the "d/l code" link would give you the actual code I'm referring to. If you do, and you run it, the array values all get initialized in the outer most scope by first. Still, in the loop, I seem to get a reference to some new value.

      Ira,

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://129783]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2019-06-19 09:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Is there a future for codeless software?



    Results (87 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!