views:

1379

answers:

4

I was wrestling with some Perl that uses hash references.

In the end it turned out that my problem was the line:

$myhash{$key} |= {};

That is, "assign $myhash{$key} a reference to an empty hash, unless it already has a value".

Dereferencing this and trying to use it as a hash reference, however, resulted in interpreter errors about using a string as a hash reference.

Changing it to:

if( ! exists $myhash{$key}) {
  $myhash{$key} = {};
}

... made things work.

So I don't have a problem. But I'm curious about what was going on.

Can anyone explain?

+2  A: 

Try this:

my %myhash;
$myhash{$key} ||= {};

You can't declare a hash element in a my clause, as far as I know. You declare the hash first, then add the element in.

Edit: I see you've taken out the my. How about trying ||= instead of |=? The former is idiomatic for "lazy" initialisation.

Chris Jester-Young
Silly me. ||=.I blame a few months' resting from Perl, in other languages.
slim
+14  A: 

Perl has shorthand assignment operators. The ||= operator is often used to set default values for variables due to Perl's feature of having logical operators return the last value evaluated. The problem is that you used |= which is a bitwise or instead of ||= which is a logical or.

As of Perl 5.10 it's better to use //= instead. // is the logical defined-or operator and doesn't fail in the corner case where the current value is defined but false.

Michael Carman
+4  A: 
Kyle
+12  A: 

The reason you're seeing an error about using a string as a hash reference is because you're using the wrong operator. |= means "bitwise-or-assign." In other words,

  $foo |= $bar;

is the same as

  $foo = $foo | $bar

What's happening in your example is that your new anonymous hash reference is getting stringified, then bitwise-ORed with the value of $myhash{$key}. To confuse matters further, if $myhash{$key} is undefined at the time, the value is the simple stringification of the the hash reference, which looks like HASH(0x80fc284). So if you do a cursory inspection of the structure, it may look like a hash reference, but it's not. Here's some useful output via Data::Dumper:

   perl -MData::Dumper -le '$hash{foo} |= { }; print Dumper \%hash'
   $VAR1 = {
             'foo' => 'HASH(0x80fc284)'
           };

And here's what you get when you use the correct operator:

  perl -MData::Dumper -le '$hash{foo} ||= { }; print Dumper \%hash'
  $VAR1 = {
            'foo' => {}
          };
friedo
Always use `Data::Dumper`, when debugging.
Brad Gilbert
$Data::Dumper::Useqq=1 can be important; by default, DD will spit out strings that include characters not immediately identifiable to the eye.
ysth