happytuna
happytuna

Reputation: 19

Hash key value changing to array reference after subroutine in perl

I'm creating keys outside and inside a subroutine on the same hash. However, after the subroutine, the values in the keys I created before the subroutine is called, are now interpreted as array references.

#!/usr/bin/perl
use module;
use strict;
use warnings;
my %hash;
my $count = 0;

my @array = ("a", "b", "c", "d");

for my $letter (@array) {
    $hash{$letter} = $count;
    $count++;
}

# need "\" to pass in hash otherwise changes
# will get lost outside of subroutine
foreach my $x (sort keys %hash) {
    print "first $hash{$x}\n";
}

module::add_ten(\%hash);

foreach my $p (sort keys %hash) {
    # $hash{$p} is printing array references, but before it was
    # printing the value I desired.  What did the subroutine do?
    print "second $hash{$p} $hash{$p}->{ten}\n";
}

and here is the module with the subroutine

package module;

sub add_ten {
my $count = 10;
    # this passes the full array as reference
    my ($hash_ref) = @_; # $hash_ref is actually %hash (yes, the % is not a typo)
    my @keys = keys $hash_ref;
    foreach my $ltr (sort keys $hash_ref) {
        $hash_ref->{$ltr} = { ten => $count };
        $count++;
    }
}
1;

here is the output:

first 0
first 1
first 2
first 3
second HASH(0x7ff0c3049c50) 10
second HASH(0x7ff0c3049bc0) 11
second HASH(0x7ff0c3049b90) 12
second HASH(0x7ff0c3049b60) 13

I'm expecting the output to be:

first 0
first 1
first 2
first 3
second 0 10
second 1 11
second 2 12
second 3 13

I modified my module:

package module;

sub add_ten {
    my $count = 10;
    # this passes the full array as reference
    my ($hash_ref) = @_; # $hash_ref is actually %hash (yes, the % is not a typo)
    my @keys = keys $hash_ref;
    foreach my $ltr (sort keys $hash_ref) {
        $hash_ref->{$ltr}{ten}=$count;
        $count++;
    }
}
1;

and the main script (needed to comment out use strict to get it to work):

#!/usr/bin/perl
use module;
#use strict;
use warnings;
my %hash;
my $count = 0;

my @array = ("a", "b", "c", "d");

for my $letter (@array) {
    $hash{$letter} = $count;
    $count++;
}

# need "\" to pass in hash otherwise changes
# will get lost outside of subroutine
foreach my $x (sort keys %hash) {
    print "first $hash{$x}\n";
}

module::add_ten(\%hash);

foreach my $p (sort keys %hash) {
    print "second $hash{$p} $hash{$p}{ten}\n";
}

But this is what I was trying to get to.

Upvotes: 0

Views: 263

Answers (1)

ikegami
ikegami

Reputation: 385734

$hash_ref is a reference to %hash, so when you change the values of the elements of the hash referenced by $hash_ref, you're changing the values of the hash %hash.

That means that when you do

 $hash_ref->{$ltr} = { ten => $count };

You are doing

 $hash{a} = { ten => 10 };

It should be no surprise that $hash{a} no longer contains zero. You'll have to change your data structure. You could use the following:

$hash{a}{value} = 0;
$hash{a}{subhash}{ten} = 10;

Upvotes: 4

Related Questions