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

Hey,

Ok, this is something that is supposed to be easy, but I cant make it work! I have the following:
my %a; my $a_ref = \%a; &resetCounters(); &add($a_ref); print $a{'modified'} . "\n"; print $a{'removed'}; sub resetCounters { $a{'added'} = 0; $a{'removed'} = 7; $a{'modified'}++; print $a{'modified'} . "\n"; } sub add { my $a_ref2 = shift; my %temp = %{$a_ref2}; $temp{'modified'}++; foreach (keys %temp) { print $_ . " " . $temp{$_} . "\n"; } }
And this prints:
1
removed 7
added 0
modified 2
1
7

But I want it to be:
1
removed 7
added 0
modified 2
2 <-- Notice!
7

What am I missing?

Thanks,
Ace

Replies are listed 'Best First'.
Re: References on hashes!
by graff (Chancellor) on Jul 08, 2005 at 03:55 UTC
    If you really want the "add" sub to modify the contents of the original "%a" hash, you'd do it like this:
    sub add { my $a_ref2 = shift; $$a_ref2{modified}++; # (update: I forgot to include this step) foreach (keys %$a_ref2) { print $_ . " " . $$a_ref2{$_} . "\n"; } }
    (note the double sigils on the hash ref: %$a_ref2 refers to the entire hash, and  $$a_ref2{$_} refers to a single hash element; another way to do the latter is $a_ref2->{$_})
      Em... what is going on here? The a_ref2's should be same hash, now shouldn't they?
      use threads; use threads::shared; my %a; my $a_ref = \%a; &resetCounters(); threads->create('add', $a_ref); threads->create('printCounters', $a_ref); #threads->create('loop', $a_ref)->join; #&printCounters(); &loop(); sub loop { while (1) { sleep 1; } } #&printCounters(); #print $a{'modified'} . "\n"; sub printCounters { my $a_ref2 = shift; print "print REF2: $a_ref2\n"; while (1) { #print "MOD: " . $a{'modified'} . "\n"; print "MOD: " . $$a_ref2{'modified'} . "\n"; sleep 1; } } sub resetCounters { $a{'added'} = 0; $a{'removed'} = 7; $a{'modified'} = 0; print $a{'modified'} . "\n"; } sub add { my $a_ref2 = shift; print "add REF2: $a_ref2\n"; while (1) { print "add\n"; $$a_ref2{'modified'}++; foreach (keys %$a_ref2) { print $_ . " " . $$a_ref2{$_} . "\n"; } sleep 5; } }
        Look more closely at "perldoc threads::shared". You have to declare variables as shared in order for different threads to see a given variable as referring to the shared data:
        my %a : shared;
        or, alternatively:
        my %a; share( %a );
        When you stringify and print the values of different references to the same underlying hash, they will still show up with different memory address values (and I can't say as I understand why that is).

        In any case, your test script does behave differently with the "share" statement included -- possibly it does what you intend.

      Ahh, yes. Natrually and ofcource! :)
Re: References on hashes!
by artist (Parson) on Jul 08, 2005 at 03:45 UTC
    In your code, within 'add' sub, %temp is a local hash and it doesn't modify the passed reference for the main program.
    --Artist