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

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

Replies are listed 'Best First'.
Shallow vs deep copy (Was Re^3: hash ref mind blow)
by ikegami (Patriarch) on Sep 24, 2008 at 21:22 UTC

    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!

        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.