http://qs321.pair.com?node_id=229934


in reply to Autovivification with hash of hashes

An alternate way to test is by using the ref function, this would avoid autovivification in a way similar to the on the first key then the existence of key beneath it option suggested. That other method might not work correctly because 'bar' may be a real key, but its content might not be an anonymous hash. In other words the key exists so the first test would pass and then cause an error similar to:
Can't use string ("key bar's value") as a HASH ref while "strict refs"
The sub routine suggested by Aristotle suffers from the same problem. However there is no mention in the orignal post as to how complex the data structure might be, but I in my own experience I have been biten by similar problems.

Perl fails as early as possible in the truth process, that is the ref fails so it doesn't bother attempting to try the second operation, thereby avoiding the problem.
Here it is with the ref and no value for 'bar'
#!/usr/bin/perl use strict; use warnings; my %foo; if(exists($foo{qux})) { print "\$foo{qux} exists"; } if(ref $foo{bar} eq 'HASH' && exists($foo{bar}{baz})) { print "\$foo{bar}{baz} exists\n"; } if(exists($foo{bar})) { print "\$foo{bar} popped into existence\n"; }
Now if we assign a scalar value to bar and try again it still works.
#!/usr/bin/perl use strict; use warnings; my %foo; $foo{bar} = "key bar's value"; if(exists($foo{qux})) { print "\$foo{qux} exists"; } if(ref $foo{bar} eq 'HASH' && exists($foo{bar}{baz})) { print "\$foo{bar}{baz} exists\n"; } if(exists($foo{bar})) { print "\$foo{bar} popped into existence\n"; }
And finally with exist && exist to produce our error.
#!/usr/bin/perl use strict; use warnings; my %foo; $foo{bar} = "key bar's value"; if(exists($foo{qux})) { print "\$foo{qux} exists"; } if(exists($foo{bar}) && exists($foo{bar}{baz})) { print "\$foo{bar}{baz} exists\n"; } if(exists($foo{bar})) { print "\$foo{bar} popped into existence\n"; }

Replies are listed 'Best First'.
Re: Re: Autovivification with hash of hashes
by pg (Canon) on Jan 26, 2003 at 05:25 UTC
    I am quite confused with your second piece of code. What does it try to demo? What is your expected result (to print out the "popped into existence" or not, I tested it, and it printed)?

    Also I don't know whether you realize that you actually used the concept of symblic reference in your second demo.

    I changed your second demo a little bit, and added comments to explain:
    use strict; #this basically disallows symblic ref use warnings; my %foo; $foo{bar} = "key bar's value"; #now you made $foo{bar} EXISTS, there i +s no need for auto-vivification to create it any more. MOST IMPORTANT +LY, this can be a symblic reference depending on how you use it, cont +inue... if(exists($foo{qux})) { print "\$foo{qux} exists"; } if(ref $foo{bar} eq 'HASH' && exists($foo{bar}{baz})) {#Here you are s +trongly suggesting a symblic reference. As for the code, the part bef +ore && obviously evaluate to false, so that exists after && will be e +valuated, but no auto-vivfication here, as $foo{bar} exists any way print "\$foo{bar}{baz} exists\n";#will not print as there is no $f +oo{bar}{baz} } if(exists($foo{bar})) {#yes print "\$foo{bar} popped into existence\n";#print out, but not pop +ped into existence, it is actually created by you } #the following is added by me $foo{bar}{baz} = 1; #violates strict refs, error, because you set $foo +{bar} to a string earlier. There is no way to create $foo{bar}{baz} i +n this context, unless you turn off use strict("refs")
    update:

    Yes, Aristotle is right, and I messed up with && and ||, Thanks for pointing out.

    However this mistake does not reduce the value of this post, and the post as a whole is still correct, especially the discussion on symbolic reference.

    I keep the mistake there (Remove the original mistake pointed out by other monks, would make other monk's reply funny, and sounds like irrelevant, and I don't do this ;-)

    "And the latter is exactly what he's talking 
    about protecting against by using ref."
    
    Doubt.
      Here you are strongly suggesting a symblic reference. As for the code, the part before && obviously evaluate to false, so that exists after && will be evaluated, but no auto-vivfication here, as $foo{bar} has been created by you earlier

      Actually, a) the ref failing will immediately lead to the entire expression failing because he is using &&, not ||. b) If it got executed, strict would cause the exists to fail with a refs stricture violation.

      And the latter is exactly what he's talking about protecting against by using ref.

      Makeshifts last the longest.

        Thank you, that is what I was trying to convey.

        I think the most important thing to do when working with structures that may contain anonymous hash refereneces is to avoid using tests that access a possibly non existent hash reference key by name, which, as far as I know, is the only way to cause autovivification. I am not sure what, other then ref could even be used. This link provides some extended examples on the subject.
        Autovivification Explained