in reply to Re^2: hash ref mind blow
in thread hash ref mind blow

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 | +-->| 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/...).

Replies are listed 'Best First'.
Re: Shallow vs deep copy (Was Re^3: hash ref mind blow)
by Anonymous Monk on Sep 25, 2008 at 15:38 UTC
    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!

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

      should be

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

      Or if you prefer,

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

      What's the point of localizing %copy? Depending on whether you do it before or after the aliasing, you either localize a variable you never use, or you localize %hash.

      But you do modify *copy, so you should localize that.

      I want to know what package does those hash textgraphs you posted.

      Notepad.