http://www.perlmonks.org?node_id=889462

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

Hi Guys,

Why does a Perl expression acting on an empty nested hash element create parents for the element eg:

#!/usr/bin/perl -w use strict; use warnings; my %a; my $a = scalar keys %{a}; print $a,"\n"; if (not exists $a{a}{a}{a}){ $a = scalar keys %{a}; print $a,"\n"; } print "End\n";

prints:

0 1 End

not

0 0 End

And is the only way to avoid this, to check the higher levels of the hash first?

Regards

Steve

Replies are listed 'Best First'.
Re: Why does perl expression in empty nested hash create parents
by Eliya (Vicar) on Feb 21, 2011 at 19:19 UTC
Re: Why does perl expression in empty nested hash create parents
by bellaire (Hermit) on Feb 21, 2011 at 19:21 UTC
    This was previously discussed here. This is known as autovivification, and is documented in the documentation for exists, and in perlref. Yes, the only way to avoid this behavior of exists is to check the higher levels of the hash first.
Re: Why does perl expression in empty nested hash create parents
by ikegami (Patriarch) on Feb 21, 2011 at 19:25 UTC
    $a{a}{a}{a}
    is short for
    $a{a}->{a}->{a}

    When the operand of a dereference (e.g. LHS of "->") is undef, it gets vivified into the right kind of reference. That means the above is short for

    ( ( $a{a} //= {} )->{a} //= {} )->{a}

    Solution? "no autovivification;"

Re: Why does perl expression in empty nested hash create parents
by furry_marmot (Pilgrim) on Feb 21, 2011 at 19:23 UTC
    Sadly, it's a feature, but it's the intermediate keys you are creating. Try this:
    print "1st run\n" if exists $a{a}; print "2nd run\n" if exists $a{a}{b}{c}; print "3rd run\n" if exists $a{a}; # prints 3rd run
    $a{a}{b} is created in order to test the existence of $a{a}{b}{c}. From perldoc -f exists:
    Note that the EXPR can be arbitrarily complicated as long as the final operation is a hash or array key lookup or subroutine name: if (exists $ref->{A}->{B}->{$key}) { } if (exists $hash{A}{B}{$key}) { } if (exists $ref->{A}->{B}->[$ix]) { } if (exists $hash{A}{B}[$ix]) { } if (exists &{$ref->{A}{B}{$key}}) { } Although the mostly deeply nested array or hash will not spring into existence just because its existence was tested, any intervening ones will. Thus "$ref->{"A"}" and "$ref->{"A"}->{"B"}" will spring into existence due to the existence test for the $key element above. This happens anywhere the arrow operator is used, including even here: undef $ref; if (exists $ref->{"Some key"}) { } print $ref; # prints HASH(0x80d3d5c) This surprising autovivification in what does not at first--or even second--glance appear to be an lvalue context may be fixed in a future release.
    But you can be smart about this. You can test for $a{a}. If it doesn't exist, any and all subkeys certainly won't exist.

    --marmot

Re: Why does perl expression in empty nested hash create parents
by Steve_BZ (Chaplain) on Feb 21, 2011 at 19:28 UTC

    Guys, thanks for your very quick responses. ++ all round! I felt that this was a difficult question to post, as some of the links suggested, without knowing the word 'autovivication' :)

    Regards

    Steve

      autovivification
Re: Why does perl expression in empty nested hash create parents
by mellon85 (Monk) on Feb 21, 2011 at 19:18 UTC
    If you search in the previous nodes this was already discussed. You need to check for each level as perl polulates the hashtable as you look into it
Re: Why does perl expression in empty nested hash create parents
by sundialsvc4 (Abbot) on Feb 22, 2011 at 15:29 UTC

    I think it was done this way because the present behavior is usually much more desirable in actual practice, most of the time.   If you want to create some arbitrarily-deep structure leading up to some piece of data that you want to store, bang! you can “just do it.”