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

Patient ones:

Perl surprised me again this morning. I wanted to *copy* an anonymous hash by dereferencing it, and then creating a new reference to it, leaving me with two references to two different hashes. So I did:

my $this = { 'name' => 'alex' }; my $that = \%{ $this }; # now i thought that $that would be an independent copy, but: $that->{'name'} = 'madonna'; print $this->{'name'}; # oh no! i'm madonna! they both referenced the same thing

This surprised me, because I thought dereferencing would make it just a 'free-floating' anonymous hash. This works fine, but is an extra line:

my $this = { 'name' => 'alex' }; my %that = %{ $this }; my $that = \%that; # now $that really is an independent copy, and: $that->{'name'} = 'madonna'; print $this->{'name'}; #alex # phew! I'm still me!

My questions are: 1) why does this happen like this? I don't really see what the difference is between the first and the second code sample. What subtlety am I missing? 2) Is there a neater way of writing the second sample, which does what I want, without using the throwaway named hash %that?

with thanks

/=\

Replies are listed 'Best First'.
Re: hash dereferencing / copying
by broquaint (Abbot) on Feb 27, 2002 at 12:59 UTC
    In your first example you're essentially copying the reference. You probably want to do something like this
    $this = { foo => bar }; $that = { %$this }; $that->{foo} = "not bar"; print $this->{foo}; __END__ bar
    This works because it creates a new anonymous hash and assigns it to $this, whereas in your first example you're just dereferencing $this and then assigning a reference to it (still with me ;-). So in your second example you're creating a new hash in %that and then assigning a reference to it, which is why it doesn't effect $this.
    HTH

    broquaint

Re: hash dereferencing / copying
by strat (Canon) on Feb 27, 2002 at 13:25 UTC
    For more complex datastructures, I like to use the perl-Module Storable to copy the content...

    Best regards,
    perl -le "s==*F=e=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

      Or, Data::Dumper (it is slower than Storable though).
      use Data::Dumper; my $this = {a => 1, b => {bb => [ 'ccc' ]}, c => 3}; # clone $this into $that my $that = eval Data::Dumper::Dumper($a);
      /prakash
Re: hash dereferencing / copying
by Ido (Hermit) on Feb 27, 2002 at 13:36 UTC
    The code my $that={%$this} will do for copying one level of references. But if you want more than one level, it won't:
    my $this={name=>'alex',array=>['one','two']}; my $that={%$this}; $that->{name}='Ido'; print $this->{name}; #alex - not affected $that->{array}[0]='three'; print $this->{array}[0];#three - affected
    In order to copy more than one level of references, use Data::Dumper:
    use Data::Dumper; my $this={name=>'alex',array=>['one','two']}; my $that=eval Dumper $this; $that->{name}='Ido'; print $this->{name}; #alex - not affected $that->{array}[0]='three'; print $this->{array}[0];#one - not affected