jrw has asked for the wisdom of the Perl Monks concerning the following question:

Why does this code generate an error (Can't use an undefined value as a HASH reference) instead of autovivifying $h{x}?
#!/usr/bin/perl -w use strict; my %h; %{$h{x}};
If I use keys(), then it does autovivify $h{x}.
#!/usr/bin/perl -w use strict; my %h; keys %{$h{x}};

Replies are listed 'Best First'.
Re: Keys() required to autovivify?
by graff (Chancellor) on Dec 30, 2007 at 06:30 UTC
    Because autovivifying will assign a "default value" of undef when you do not supply an assignment (rhs) value as part of the autovivifying expression.

    In your first example, the enclosure within  %{...} requires that the enclosed expression must yield a reference to a hash (not doing so is an error), and of course, undef cannot be interpreted as a hash ref.

    In your second example, the "keys()" function is only looking at keys in the hash, not at values, so it doesn't matter that the "default value" being assigned to $h{x} happens to be undef.

    UPDATE: When I first wrote and posted the above, it seems I was missing an important point, and I think GrandFather came closer to getting it right in his reply below: there is something "DWIM-ishly" odd going on with the keys() function, and I personally cannot explain why the second snippet in the OP does not trigger an error. On reflection, it strikes me as strange, and I understand jrw's continuing sense of confusion. (But ikegami and shmem have helped a lot with their replies, and I am less confused now.)

      I don't understand what you're saying. In the second example, %{$h{x}} is being autovivified by the use of keys() to create an empty hash at $h{x}. In the first example, the exact same expression, but without the call to keys(), is a syntax error.

        Using $h{x} is sufficient to autovifiy a key/value pair if there is no key/value pair for the key 'x' in the hash %h.

        In the first case you give, the key 'x' is added to the hash (the $h{x} bit does that) with the value undef. The %{...} then tries to dereference the undef and generates the error that you see.

        The second case is equivalent to:

        my $ref = undef; keys %{$ref}; # or: keys %$ref;

        which, somewhat surprisingly, is fine and is about the same as asking for the keys of an empty hash. I guess this is an element of DWIM coming into play - if you ask for the keys of a hash reference that you haven't gotten around to assigning any key/value pairs to yet, then a list of not keys (and no errors generated) is a pretty reasonable thing to do.


        Perl is environmentally friendly - it saves trees
Re: Keys() required to autovivify?
by ikegami (Patriarch) on Dec 30, 2007 at 07:06 UTC

    Your code is overly complicated. $h{$x} can be replaced with just $h.

    >perl -le"%{ $h }; print $h ? 1 : 0" 0 >perl -le"%{ $h } = (); print $h ? 1 : 0" 1 >perl -le"keys %{ $h }; print $h ? 1 : 0" 1 >perl -le"sub {}->( %{ $h } ); print $h ? 1 : 0" 1

    In the first program, the hash isn't required, so it isn't created.
    In the subsequent programs, a hash is required, so it is autovivified.

    I can't explain why some built-ins don't autovivify the hash, even though it needs to be flattened.

    >perl -le"sub f {} f( %{ $h } ); print $h ? 1 : 0" 1 >perl -le"print( %{ $h } ); print $h ? 1 : 0" 0
      Well, actually my code could just be replaced with perl -e ''. But this is just my demo code to show the problem that I encountered.

      My real code looked like:

      if (%{$h{x}}) { ... }
      by which I meant to execute the body of the if statement only if $h{x} (was a hash and) had at least one element. But instead I got a syntax error. I had to switch to
      if (keys %{$h{x}}) { ... }
      which was more than I wanted to say.

      I was wondering why the use of keys() made perl smart enough to autovivify my hash, but the use of %{$h{x}} wasn't enough to cause it to autovivify (and then return a false value since the autovivified hash value was empty).

        only if $h{x} (was a hash and) had at least one element

        Then test whether the value of $h{x} actually is a hash reference.

        If you say keys %{$h{x}} it is assumed you know what you are doing and want autovivifying, while dereferencing an undef value could just be a mistake. strict 'refs' catches that - that is what strict is about ;-)

        By using keys you look inside the box (= the hashref), so perl autovivifies it, if it doesn't exist; by dereferencing you look at the box only.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      I can't explain why some built-ins don't autovivify the hash, even though it needs to be flattened.

      It's not about hash flattening, but the fact that arguments are passed into subroutines as references. So saying f( %{ $h } ); for an undefined $h looks up keys and values, which causes the container to spring into existence as a hash reference and be assigned to $h. That is necessary since the arguments to subs are potential candidates for assignment (lvalues)

      perl -MO=Concise -le 'my $h;sub f {} f( %{ $h } );' a <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 3 <0> padsv[$h:1,4] vM/LVINTRO ->4 4 <;> nextstate(main 4 -e:1) v ->5 9 <1> entersub[t4] vKS/TARG,1 ->a - <1> ex-list K ->9 5 <0> pushmark s ->6 7 <1> rv2hv[t3] lKM/1 ->8 - <@> scope sK ->7 - <0> ex-nextstate v ->6 6 <0> padsv[$h:1,4] sM/DREFHV ->7 - <1> ex-rv2cv sK/1 ->- 8 <#> gv[*f] s ->9

      (note the line padsv[$h:1,4] sM/DREFHV with the M flag), which is not the case with print.

      perl -MO=Concise -le 'my $h;print( %{ $h } )' 9 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 3 <0> padsv[$h:1,3] vM/LVINTRO ->4 4 <;> nextstate(main 3 -e:1) v ->5 8 <@> print vK ->9 5 <0> pushmark s ->6 7 <1> rv2hv[t2] lK/1 ->8 - <@> scope sK ->7 - <0> ex-nextstate v ->6 6 <0> padsv[$h:1,3] s ->7

      Since print doesn't comprise modifcation of it's arguments, the hashref isn't created.

      That's the most concise explanation of this oddity I can conceive up to now...

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

        Function arguments are always passed by reference, so they need to be real. But print's not a function. Keep in mind that the builtin functions are often called "named operators" and that Deparse shows a "print" op, not a "entersub" op. I suspect it's more along the lines of print and other builtins have their arguments built specially.

        Just guessing.

        By the way, I was getting similar results to print when using assignments.

Re: Keys() required to autovivify?
by ysth (Canon) on Dec 31, 2007 at 01:58 UTC
      Thanks! I think this is the answer I was looking for. Keys() is supplying some extra magic to cause autovivification whereas plain scalar context unfortunately doesn't. Oh well. Unfortunately, I bet on if (%{$h{x}}) autovivifying because I knew if (keys %{$h{x}}) did.
Re: Keys() required to autovivify?
by Anonymous Monk on Jan 04, 2008 at 10:31 UTC
    $h{x} is undefined. In order for something to be used in a %{ $something } construct, ref( $something ) eq 'HASH'. and ref( undef ) is undef, not HASH. While I'm not sure, I suspect the error occurs because %{$h{x}} is being passed by a prototype (namely (\%)) as a reference, as if you called keys(\%{$h{x}}), *I've forgotten the rest of my post, and I'm in a non-Perl mode now, so I can't complete it. Sorry*