views:

191

answers:

4

Can some one help me understand the output of this Perl program:

use Data::Dumper;
my %hash;
$hash{hello} = "foo";
$hash{hello}{world} = "bar";
print $hash{hello} . "\n";
print $hash{hello}{world} . "\n";
print Dumper(\%hash);

And the output:

foo
bar
$VAR1 = {
          'hello' => 'foo'
        };

Where is the "foo" coming from? How come it isn't printed out by dumper?

Note that if I swap the order of the assignments:

use Data::Dumper;
my %hash;
$hash{hello}{world} = "bar";
$hash{hello} = "foo";
print $hash{hello} . "\n";
print $hash{hello}{world} . "\n";
print Dumper(\%hash);

my output is what I expect:

foo

$VAR1 = {
          'hello' => 'foo'
        };

EDIT: I know that use strict; would catch this, but I'm more interested in know how the string "foo" is still being printed.

+16  A: 

Your code is missing

use strict;
C:\Temp> hui
Can't use string ("foo") as a HASH ref while "strict refs" in use at 
C:\Temp\hui.pl line 7.

Make sure all your scripts start with:

use strict;
use warnings;

Given:

$hash{hello} = "foo";

$hash{hello} is NOT a hash reference.

$hash{hello}{world} = "bar";

treats the string "foo" as a hash reference and creates the hash %main::foo and sets $foo{world} to "bar".

When you do:

print Dumper \%hash;

it only prints the contents of %hash. Whereas, when you do

print $hash{hello}{world} . "\n";

it prints $foo{world}.

Without strict, you do not get to find out that the script has trampled all over the package name space.

Add a

print Dumper \%main::;

or

print Dumper \%main::foo;

to inspect the symbol table after you run this.

Sinan Ünür
Adding use strict finds problems with this, but it doesn't tell me how I am getting the output that I am. This is more of a Perl internals question than a "plz fix my codez"
tster
What's happening is it's autivivifying a variable called `%foo` (because that's what happens when you use a string as a reference). Add `print Dumper(\%foo)` to the end of your code to see the dangerous results.
Chris Lutz
Chris, that is awesome, thanks!
tster
+1  A: 

If you were using strict, you'd get an error with your script.

Can't use string ("foo") as a HASH ref while "strict refs" in use at ...

jamessan
+2  A: 

Basically the string "foo" is the only value of %hash, but (due to non-strictyness) %foo is being created that contains (world => "bar")

Cebjyre
+1  A: 

Autovivification only works when the you start with undefined values. Since your $hash{hello} isn't an undefined value, you don't autovivify the next level. Instead, you end up using $hash{hello} as a soft reference.

brian d foy