Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point of this kind of code?

Tags:

perl

{%{$self->param}}

It does hash expand, and then create another hash reference.

But isn't {%{$self->param}} the same as $self->param? Why does the code bother doing the trick?

like image 962
asker Avatar asked Aug 29 '11 06:08

asker


3 Answers

It copies the hash. Consider the following snippet:

use Data::Dumper;

my $foo = { a => 1, ar => [1] };
my $bar = {%$foo};

$bar->{b} = 2;
push @{$bar->{ar}}, 4;

print Dumper $foo;
print Dumper $bar;

It prints

$VAR1 = {
          'a' => 1,
          'ar' => [
                    1,
                    4
                  ]
        };
$VAR1 = {
          'a' => 1,
          'b' => 2,
          'ar' => [
                    1,
                    4
                  ]
        };

So you can see that the copy is shallow: Scalars are copied over, even if they are references. The referenced objects are the same (in this example the array referenced by ar).

like image 171
musiKk Avatar answered Oct 12 '22 15:10

musiKk


Although both {%{$self->param}} and $self->param are references to a hash, they do not refer to a hash stored in the same location.

The first expression dereferences $self->param to a hash, and returns a reference to an anonymous hash. Within the outer braces, %{$self->param} is actually expanded and copied temporarily, and then a reference to this temporary copy is returned, not to the old hash.

like image 41
Blagovest Buyukliev Avatar answered Oct 12 '22 14:10

Blagovest Buyukliev


This code actually creates a copy hash (shallow copy of keys and values, but not deep copy), reference to which is returned and returns reference to it.

If some sub returns reference to a hash and you change something in it, you actually are changing values in original hash. To avoid this we sometimes need to copy whole hash (or array) before making any changes.

Here's example:

sub get_hashref {
    my $hashref = shift;
    return $hashref;
}

my %hash = (foo => 'bar');

my $ref = get_hashref(\%hash);
$ref->{foo} = 'baz'; # Changes 'foo' value in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n";   # 'baz'

# But!

$ref = {%{ get_hashref(\%hash) }};
$ref->{foo} = 42; # No changes in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n";   # '42'

To be understood better, {%{ $self->param }} may be expanded to:

my $ref = $self->param; # Ref to original hash
my %copy = %{$ref}; # Copies keys and values to new hash
my $ref_to_copy = {%copy}; # get ref to it

You also may omit last step if you need hash but not reference to it.

like image 31
yko Avatar answered Oct 12 '22 13:10

yko