Perl modifying hash reference in subroutine

Sid picture Sid · Apr 13, 2012 · Viewed 13.2k times · Source

I am having trouble understanding the hash references and changing the hash in place, instead of returning it. I want to write a sub routine which will return a value from hash and also modify the hash. I was facing some issues while coding for it. So, I wrote the following basic code to understand modifying the hash in place.

#!/usr/local/bin/perl
#Check hash and array references
#Author: Sidartha Karna
use warnings;
use strict;
use Data::Dumper;

sub checkHashRef{
   my ($hashRef, $arrVal) = @_;
   my %hashDeref = %{$hashRef};

   $hashDeref{'check'} = 2;           
   push(@{$arrVal}, 3);

   print "There:" ;
   print Dumper $hashRef;      
   print Dumper %hashDeref;           
   print Dumper $arrVal

}


my %hashVal = ('check', 1);
my @arrVal = (1, 2);

checkHashRef(\%hashVal, \@arrVal);

print "here\n";
print Dumper %hashVal;
print Dumper @arrVal;

The output observed is:



    There:$VAR1 = {
          'check' => 1
        };
    $VAR1 = 'check';
    $VAR2 = 2;
    $VAR1 = [
          1,
          2,
          3
        ];
    here
    $VAR1 = 'check';
    $VAR2 = 1;
    $VAR1 = 1;
    $VAR2 = 2;
    $VAR3 = 3;

From the output, I inferred that, changes to hashDeref are not modifying the data in the reference. Is my understanding correct? Is there a way to modify the hash variable in place instead of returning it.

Answer

mu is too short picture mu is too short · Apr 13, 2012

This is making a (shallow) copy of %hashVal:

my %hashDeref = %{$hashRef};

The hash-ref $hashRef still points to %hashVal but %hashDeref doesn't, it is just a copy. If you want to modify the passed hash-ref in-place, then work with the passed hash-ref:

sub checkHashRef{
   my ($hashRef, $arrVal) = @_;
   $hashRef->{'check'} = 2;
   #...

That will leave your changes in %hashVal. In the array case, you never make a copy, you just dereference it in-place:

push(@{$arrVal}, 3);

and the change to $arrVal shows up in @arrVal.