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

First off, thank you to everyone who stepped up to help me with this question. So I followed the advice that was given and wrote a little test script which went something like this:
my @array; my %hash; &callaFunction(); &callaFunction(); &callaFunction(); foreach my $element ( @array ) { my %localHash = %{$element}; # print %localHash's contents } sub callaFunction { # fill %hash with random info push ( @array, {%hash} ); }
And this script worked perfectly well. Each index of the array was unique (as opposed to if I made calls to push @array, %hash; in which case every index of the array contained a reference to the same hash, with whatever values were put in the hash last).

However, when, armed with this newfound knowledge, I sallied forth into my main program and applied what I had learned, I was thoroughly vexed to find that my original problem had once again reared its ugly head! That is to say, although I called

push ( @globalArray, {%globalHash} );
I found that each element of @globalArray had the same values within it. So somehow, although I created anonymous hashes to push onto the array, a single reference to the same hash was pushed onto the array again and again.

Monks, I am at a loss. The inner magics of references are but newly known to me. So my question to you, O monks whose wisdom shines like a stream of bat urine on a moonlit night, is this: how could the call to push which I describe above still result in the same reference being pushed onto my array repeatedly?

Some people drink from the fountain of knowledge, others just gargle.

  • Comment on Night of the Day of the Dawn of the Son of the Bride of the Return of the Attack of the Revenge of the Horrors of References and Complex Data Structures
  • Select or Download Code

Replies are listed 'Best First'.
Re: Night of the Day of the Dawn of the Son of the Bride of the Return of the Attack of the Revenge of the Horrors of References and Complex Data Structures
by chromatic (Archbishop) on Feb 07, 2001 at 03:54 UTC
    I'm still pretty sure it's the global variable that's messing you up. Consider the odd-but-possible case where %globalHash gets new values occasionally:
    my (@array, %hash); do_something($_) for (1 .. 3); sub do_something { my $num = shift; $hash{$num} = $num; push @array, { %hash }; } use Data::Dumper; print Dumper(\%hash); foreach my $href (@array) { my ($key, $value); print "Hash ($href):\n"; foreach $key (keys %$href) { $value = $href->{$key}; print "\t$key => $value\n"; } }
    Each time through do_something(), not only does %hash get new data, but the hash reference pushed onto @array gets the old data.

    This may or may not be what you want. In fact, I'm really not sure what you want. Instead of asking "How do I fix this bit of code that isn't working?" perhaps you should ask "Here is a textual description of the task I am trying to accomplish. What methods might I use to perform this task?" (XYZ Questions)

Re: Night of the Day of the Dawn of the Son of the Bride of the Return of the Attack of the Revenge of the Horrors of References and Complex Data Structures
by Yoda (Sexton) on Feb 07, 2001 at 05:15 UTC
    Does your hash have to be global? This should work. I'm not 100% sure becuase I have no where to test it. A good reference is perldsc.
    my @array; &callaFunction(); &callaFunction(); &callaFunction(); foreach my $element ( @array ) { my %localHash = %{$element}; # print %localHash's contents } sub callaFunction { my $hash = {}; # fill $key and $value with some random info here $hash->{$key} = $value; push ( @array, $hash ); # if you still need a global hash assign $hash to it here. }
Re: Night of the Day of the ...
by runrig (Abbot) on Feb 07, 2001 at 03:18 UTC
    A different hash reference should be pushed onto the array every time in the situation you describe. However, its possible that the contents of those hashes are the same (use Data::Dumper to see the contents, if they are the same references also, it would show that).

    I still question the need to use the same global hash everywhere, but if you need to push a snapshot of the hash onto the array, the 'push @array, { %hash }' should work for a simple hash, or if you need a deeper copy, then see dclone in Storable.

Re: Night of the Day of the Dawn of the Son of the Bride of the Return of the Attack of the Revenge of the Horrors of References and Complex Data Structures
by geektron (Curate) on Feb 07, 2001 at 03:15 UTC
    try
    push ( @array, ${%hash} );

    i don't see what your original line does. {%hash} doesn't do the de-referencing i think you're looking for.

    Update i stand corrected.

      Sure it does...
      perl -we "use Data::Dumper; %x = (1,2,3,4); $y = {%x}; print join $/, +$y, \%x, Dumper($y);" HASH(0x1a7f1a8) HASH(0x1a72abc) $VAR1 = { '1' => 2, '3' => 4 };
Re: Night of the Day of the blah blah blah...
by MeowChow (Vicar) on Feb 07, 2001 at 03:00 UTC
    It would help if you posted a minimial test case that exhibits the behaviour you describe.
       MeowChow                                               
                    print $/='"',(`$^X\144oc $^X\146aq1`)[-2]
      That's my problem. The minimal test case DOESN'T exhibit the behavior I describe! The minimal test case performs perfectly. It is only when I use what seems to my eyes to be the exact same code in a larger program that this stops working. Hence, my thorougly perplexed state of mind. So I am wondering what sorts of reference behavior I've never even heard of might be able to cause references to act this strangely. Some people drink from the fountain of knowledge, others just gargle.
        Usually when this happens, I take the code that exhibits the problem, and begin chiseling out piece by piece, sculpting the code into my working minimal test case. Eventually, the problem disappears, and you find your bug.
           MeowChow                                               
                        print $/='"',(`$^X\144oc $^X\146aq1`)[-2]