in reply to hash ref mind blow

%copy is just a shallow copy. That means, it shares the references to all { drinks => ... } hashes with %hash. If you want to do a deep copy that copies all values and all referenced data structures, have a look at Storable::dclone:

my %copy = dclone(\%hash);

should be all you need.

Replies are listed 'Best First'.
Re^2: hash ref mind blow
by Anonymous Monk on Sep 24, 2008 at 16:23 UTC
    Got it. Thanks!! And I thought I knew perl... Never heard of shallow copies. Anybody knows which perldoc has some material on this? perlref doesn't seem to mention them at all. -rod

      You might think of

      $hash{a}{drinks}=1; $hash{b}{drinks}=2;

      as a single hash, but that's not the case. There are three:

      • %hash
      • %{ $hash{a} }
      • %{ $hash{b} }
      +-------+ +----------+ +-----------+ +-------------+ | %hash | +-->| Anon Ref | +->| Anon hash | +->| Anon scalar | +-------+ | +----------+ | +-----------+ | +-------------+ | a ----+ | addr ----+ | drinks ----+ | 1 | | b -----+ +----------+ +-----------+ +-------------+ +-------+ | | +----------+ +-----------+ +-------------+ +->| Anon Ref | +->| Anon hash | +->| Anon scalar | +----------+ | +-----------+ | +-------------+ | addr ----+ | drinks ----+ | 2 | +----------+ +-----------+ +-------------+

      When you do %copy = %hash (which you wrote as %copy = %{ \%hash }), you are copying the keys and values of %hash. So what are the keys and values of %hash?

      >perl -e"$h{a}{d}=1; $h{b}{d}=2; print qq{$_: $h{$_}\n} for keys %h;" a: HASH(0x22534c) b: HASH(0x2253a0)

      That's all that's copied, nothing more. It will not make a copy of the referenced value and make a new reference to it. It simply copies the references. You end up with

      +-------+ +----------+ +-----------+ +-------------+ | %hash | +-->| Anon Ref | +----->| Anon hash | +->| Anon scalar | +-------+ | +----------+ | +-----------+ | +-------------+ | a ----+ | addr -----+ | drinks ----+ | 1 | | b -----+ +----------+ | +-----------+ +-------------+ +-------+ | | | +----------+ | +-----------+ +-------------+ +->| Anon Ref | | +-->| Anon hash | +->| Anon scalar | +----------+ | | +-----------+ | +-------------+ | addr --------+ | drinks ----+ | 2 | +----------+ | | +-----------+ +-------------+ | | +-------+ +NEW-------+ | | | %copy | +-->| Anon Ref | | | +-------+ | +----------+ | | | a ----+ | addr -----+ | | b -----+ +----------+ | +-------+ | | | +NEW-------+ | +->| Anon Ref | | +----------+ | | addr --------+ +----------+

      What you want is to do is to copy referenced values as well, and to do recursively, so that you end up with the following:

      +-------+ +----------+ +-----------+ +-------------+ | %hash | +-->| Anon Ref | +->| Anon hash | +->| Anon scalar | +-------+ | +----------+ | +-----------+ | +-------------+ | a ----+ | addr ----+ | drinks ----+ | 1 | | b -----+ +----------+ +-----------+ +-------------+ +-------+ | | +----------+ +-----------+ +-------------+ +->| Anon Ref | +->| Anon hash | +->| Anon scalar | +----------+ | +-----------+ | +-------------+ | addr ----+ | drinks ----+ | 2 | +----------+ +-----------+ +-------------+ +-------+ +NEW-------+ +NEW--------+ +NEW----------+ | %copy | +-->| Anon Ref | +->| Anon hash | +->| Anon scalar | +-------+ | +----------+ | +-----------+ | +-------------+ | a ----+ | addr ----+ | drinks ----+ | 1 | | b -----+ +----------+ +-----------+ +-------------+ +-------+ | | +NEW ------+ +NEW--------+ +NEW----------+ +->| Anon Ref | +->| Anon hash | +->| Anon scalar | +----------+ | +-----------+ | +-------------+ | addr ----+ | drinks ----+ | 2 | +----------+ +-----------+ +-------------+

      That's called a "deep copy" because it copies every level of the data structure. In contrast, a simple assignment is called a "shallow copy" because it only copies the immediate value (scalar/hash/array/...).

        Yeah, I thought that %{ _ref_ } created an alias, but now I've learned it just shallow copies the struct.

        It's coincidental, but everytime I used it as reference passed to subs, I added subkeys and everything worked as an alias. To my surprise, when I added a root key to %copy and it didn't change %hash my world came tumbling down.

        So it's back to $$copy->{key} stuff, as

        use strict; local our %copy; *copy = \%hash;

        Looks so unscoped to my personal perl taste. And Data::Alias will not cpan into my Strawberry perl, complaining about requiring perl 5.8.9 on Win32...

        BTW ikegami, wow!

        Now... I want to know what package does those hash textgraphs you posted. Cos Data::Dumper doesn't get even close to that kind of representation!