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

I'm a bit puzzled. I have a complex data structure like:
$foo = { 'SOMETHING_01' => { 'CLASS' => [ { 'VALUE' => 'BUBBLE' } ], } }

obviously tons of references. My understanding was that %{$foo->{'SOMETHING_01'}} would dereference SOMETHING_01 so that I could copy and change the data without messing up $foo.
I'm doing:

my $fee; %{$fee->{'SOMETHING_02'}} = %{$foo->{'SOMETHING_01'}}; $fee->{'SOMETHING_02'}{CLASS}[0]{VALUE} = 'SQUEEK';

but now $foo is changed. (!) Any ideas on how I can accomplish this?

Thanks,
Alex

Replies are listed 'Best First'.
Re: Forcing dereference
by shemp (Deacon) on Oct 15, 2004 at 17:04 UTC
    What you're really copying is a reference to the secondary data structure, but what is being referenced is still the same thing. You need to make a deep copy. Heres one way to do it:
    use Storable qw(dclone); my $fee->{'SOMETHING_02'} = dclone($foo->{'SOMETHING_01'});
    You'll probably want to read about the Storable module at cpan.

      Exactly right. Let me illustrate what is happening. Your data structure looks like (simplified):

      $foo = { 'SOMETHING_01' => {'CLASS' => [ {'VALUE' => 'BUBBLE' } ] } }
      Let's do a little analysis, assuming $foo retains its value:
      $bar = $foo->{SOMETHING_01}; # $bar is hash reference $caz = %{$foo->{SOMETHING_01}; # $caz is a hash print $caz{'CLASS'}; # 'ARRAY(...)' - an array reference print $caz{'CLASS'}->[0]; # 'HASH(...)' - a hash reference
      Note that when you copy a reference, you aren't copying the data -- you're making a new reference to the same data. By using the deep-copy method of the parent, you copy the data contained in the reference instead of the reference itself.

      radiantmatrix
      require General::Disclaimer;
Re: Forcing dereference
by borisz (Canon) on Oct 15, 2004 at 17:13 UTC
    Yes, since you copy copy only a reference to something 2. Not the data. You want a deepcopy or clone. There are several modules that can do this. Clone::PP, Storable, Data::Dumper and lots more.
    Boris
Re: Forcing dereference
by ikegami (Patriarch) on Oct 15, 2004 at 17:51 UTC

    Just trying to explain the "why".

    It does prevent you from messing up $foo (and %$foo, including $foo->{'SOMETHING_01'}), but it doesn't prevent you from messing up that to which $foo->{'SOMETHING_01'} points, if $foo->{'SOMETHING_01'} is a reference. That's why you need to do a deep copy, as shown in other replies.

    If that doesn't make sense, check out this example:

    use Data::Dumper; { my $ref = [ 'moo' ]; my %h1 = ( key1 => 'val1', key2 => $ref ); print("$_ => $h1{$_}\n") foreach (keys(%h1)); # prints: # key1 => val1 # key2 => ARRAY(0x1abf040) print Dumper \%h1; # { # 'key1' => 'val1', # 'key2' => [ # 'moo' # ] # } my %h2 = %h1; # Shallow copy. delete($h2{'key1'}); $h2{'foo'} = 'bar'; $h2{'key2'}[0] =~ s/m/b/; print("$_ => $h1{$_}\n") foreach (keys(%h1)); # prints: # key1 => val1 # key2 => ARRAY(0x1abf040) # and not: # foo => bar # key2 => ARRAY(0x1abf040) print Dumper \%h1; # { # 'key1' => 'val1', # 'key2' => [ # 'boo' # ] # } }

    Note that %h1 never changes. Only @$ref changes. It's the same as in your code. You're changing that to which $foo->{'SOMETHING_01'} points while protecting the hash ref at $foo->{'SOMETHING_01'}.