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

Dear Monks, I have a hash, where value to a key is a nested hash in itself. Somewhere down the line in process,I expand the single key, into multiple keys/exploded keys, and process the value of single key (nested hash) to introduce a minor change and assign it to exploded keys, such that values in key are unique. But the dumper gives me a reference as value, that too to a refering to a single value, instead of expanded hash each having unique value. Below is the truncated code and Dumper output.
if ($padinstance =~/^\s*(\w+)\[\s*(\d+)\s*\:\s*(\d+)\s*\]\s*$/) { #Check and modify simultaneously my $padword = $1; my $msb = $2; my $lsb = $3; my %hashcopy = %{$topxls_hash_ref->{$hier}->{$padinstance}}; for (my $counter = 0; $counter <= $msb - $lsb; $counter ++) { my %newhash = %hashcopy; foreach my $chk_key (keys (%hashcopy)) { if ($chk_key eq "MODE") { ## For each mode check type and do action foreach my $mode (keys (%{$hashcopy{MODE}})) { if ($hashcopy{MODE}->{$mode}->{TYPE} eq "O") { foreach my $chk_mode_key (keys (%{$hashcopy{MODE} +->{$mode}})) { if ($chk_mode_key eq "ENABLES") { foreach my $enable_sig (@{$hashcopy{MODE}->{ +$mode}->{ENABLES}}) { if ($enable_sig =~/\w+/) { print Dumper(\%hashcopy); if (defined ($hashcopy{MODE}->{$mode}- +>{"EN\@$enable_sig"}) && $hashcopy{MODE}->{$mode}->{"EN\@$enable_sig" +} =~/\w+/) { my $array_index = 0; foreach my $enable_sig_iter (@{$ha +shcopy{MODE}->{$mode}->{"EN\@$enable_sig"}}) { print "In mode for $mode for ENABLES $enable +_sig_iter\n"; if ($enable_sig_iter =~/^(\s*\w+ +)\s*\[\s*(\d+)\s*\:\s*(\d+)\s*\]/) { my $prefix_word = $1; my $local_msb = $2; my $local_lsb = $3; if ($local_msb - $local_lsb = += $msb - $lsb) { my $token = $local_lsb + $ +counter; my $newsignal = "$prefix_w +ord\[$token\]"; $newhash{MODE}->{$mode}->{ +"EN\@$enable_sig"}->[$array_index] = $newsignal; } else { + return -1; } } $array_index ++; } } } }
Similar to ENABLE key, I have many other keys on which I am doing the operation and at end, I am attaching back the value of %newhash
$topxls_hash_ref->{$hier}->{$padinstance_new} =\%newhash;
however, after first iteration, modification in %newhash also modifies %hashcopy. I am not able to understand the reason behind such behaviour in nested hashes. Please help! Please let me know, where I am going wrong. While searching after posting, I came across that this is more to do with shallow copy. I need to make a deep copy.

Replies are listed 'Best First'.
Re: Hash value, containing a reference to some value of hash, not the intended behaviour.
by cdarke (Prior) on Mar 14, 2011 at 11:34 UTC
    You need to do a deepcopy. Replace:
    my %newhash = %hashcopy;
    With something like this:
    use Storable qw(dclone); my %newhash = %{dclone(%hashcopy)};
    We could use thaw and freeze, but a simpler interface is provided in dclone which carries out both operations. There is also a Clone module on CPAN.
Re: Hash value, containing a reference to some value of hash, not the intended behaviour.
by Anonymous Monk on Mar 14, 2011 at 11:00 UTC
    however, after first iteration, modification in %newhash also modifies %hashcopy. I am not able to understand the reason behind such behaviour in nested hashes. Please help!

    Its simple, it boils down to

    my %newhash; my %hashcopy; my %other; $hashcopy{something} = \%other; $newhash{something} = \%other;
    $newhash{something} and $hashcopy{something} are the same thing, a reference to %other;
      Got it! made a deep copy to make things work