hansi
hansi

Reputation: 2298

perl: added hash entry in a subroutine is lost

Why is the hash empty on the second call of printHash?

my %hash = ();
addToHash(\%hash);
printHash(\%hash);

sub addToHash {
  my %hash = %{$_[0]};
  $hash{"test"} = "test";
  printHash(\%hash);
} 

sub printHash {
  print "printHash: \n";
  my %hash = %{$_[0]};
  foreach my $key (keys %hash) {
      print "key: $key, value: $hash{$key}\n";      
  }
}

Output:

printHash:

key: test, value: test

printHash:

Upvotes: 2

Views: 379

Answers (4)

snoofkin
snoofkin

Reputation: 8895

you may want to use the hash alias (in your case, $_[0]) directly.

Upvotes: 0

chepner
chepner

Reputation: 531125

In

sub addToHash {
  my %hash = %{$_[0]};
  $hash{"test"} = "test";
  printHash(\%hash);
}

my %hash creates a new hash into which you copy the hash referenced by the argument. You want

sub addToHash {
  my $hr = $_[0];
  $hr->{"test"} = "test";
  printHash($hr);
}

in order to modify the original hash.

Upvotes: 6

mob
mob

Reputation: 118605

Because the addToHash function is adding a key-value pair to a copy of the first %hash variable.

my %hash = %{$_[0]}

dereferences the hash reference in $_[0] but the assignment to my %hash creates a new copy of the hash's contents. If you want addToHash to affect the input hash reference, you still need to work with it as a hash reference:

sub addToHash {
    my $hashref = $_[0];
    $hashref->{"test"} = "test";
    printHash( $hashref );
}

Try this exercise to get a sense of the difference between using hashes and references to hashes.

%a = (foo => "bar");       # hash
$b = { foo => "bar" };     # reference to hash

%c = %a;                   # new copy of a hash
$c{"foo"} = "baz";         # changes the copy of %a, but not %a
print $a{"foo"};           # still outputs "bar"

$d = $b;                   # $d is reference to same hash that $b points to
$d->{"foo"} = "baz";       # changes $b
print $b->{"foo"};         # now outputs "baz"

$e = \%a;                  # $e is a reference to hash %a
$e->{"foo"} = "baz";       # changes %a
print $a{"foo"};           # now outputs "baz"

Upvotes: 5

w.k
w.k

Reputation: 8376

You have local %hash in your subrutine and so you are not changing the one in main-scope.

Upvotes: 1

Related Questions