Tomatobot
Tomatobot

Reputation: 41

deprecated "Can't use a hash as a reference" perl error in legacy code

We've got some legacy code throwing up the "Can't use a hash as a reference" perl error. The previous "fix" was to turn off warnings, but new perl has made the warning a hard error and so now someone's got to actually fix the problem.

The code looks like this...

foreach my $a (keys %{$x->{'y'}}) {
        my $b = %$x->{'y'}->{$a};
        <some other stuff>
}

My understanding is that something like %j->{'k'} should be converted into $j{'k'}, but the %$ thing with two pointers is more than I can process, given that I only understand this at the most general of levels.

It seems that only the line within the loop is causing the error, but I included the foreach for reference.

Is it clear what the original author is attempting to do and is there an obvious fix that that will clean this up once and for all?

Thanks.

Upvotes: 2

Views: 2817

Answers (2)

melpomene
melpomene

Reputation: 85767

It looks like the idea is to iterate over the entries in the hash referenced by $x->{'y'}. The foreach loop sets $a to each key in turn. The loop body would then assign the corresponding value to $b.

From the keys expression we can see that $x must contain a reference to a hash, and that the value under the key 'y' must be a reference to another hash. From that you can get the value under $a by doing

my $b = $x->{'y'}->{$a};
# or: 
my $b = $x->{y}{$a};  # if you don't like typing

The problem with your original code is the %$x->{...} part. %$x dereferences the reference in $x, so what you get as a result is an actual hash. The ->{...} operator then tries to dereference it again, which makes no sense (as the error message says, a hash is not a reference). Just drop the % and let ->{...} do the work.

(Alternatively, if you're feeling crazy, you can do (\%$x)->{'y'}->{$a}. In addition to % (to dereference the reference in $x), we use \ (to take a reference to the hash we just got), which can then correctly be dereferenced (again) by ->{...}.)


For the future, blindly silencing warnings is usually not a good idea, especially if they tell you about bugs in your code.

Upvotes: 1

ysth
ysth

Reputation: 98398

Just dropping the % should do it. I can't imagine anything else that could have been meant.

Upvotes: 4

Related Questions