Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Why does testing a key create a hash?

by johnnywang (Priest)
on Aug 17, 2005 at 21:49 UTC ( [id://484615]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, the following is a source of a bug that took me awhile to figure out.
use strict; my $hash = undef; print "shouldn't print\n" if $hash; # prints nothing print 1 if $hash->{1}; # should be a no-op, but it makes $hash to be { +} print "Still shouldn't print, but it does.\n" if $hash; # prints
I thought a test such as "if $hash->{1}" wouldn't change $hash, but apparently it does. Is this a well-known behavior, and what's the reason for it? I fully appreciate that "$hash->{1} = 1;" would create the hash.

Replies are listed 'Best First'.
Re: Why does testing a key create a hash?
by Roger (Parson) on Aug 17, 2005 at 22:01 UTC
    Yes, this is a well known behavior/feature called autovivification. It basically means that Perl will create the variable on the fly. The use strict pragma will only stop autovivification of variables, but not hash elements. To test for the existance of a hash key with out creating it, you must use the exists function. Use along the lines of if exists $hash->{1} instead.

    perldoc -f exists exists EXPR Given an expression that specifies a hash element or array element, returns true if the specified element in the hash or array has ever been initialized, even if the corresponding value is undefined. The element is not autovivified if it doesn't exist. print "Exists\n" if exists $hash{$key}; print "Defined\n" if defined $hash{$key}; print "True\n" if $hash{$key}; print "Exists\n" if exists $array[$index]; print "Defined\n" if defined $array[$index]; print "True\n" if $array[$index]; A hash or array element can be true only if it's defined, and defined if it exists, but the reverse doesn't necessarily hold true. ....
      Use if exists $hash->{1} instead.

      Nope, that will still cause $hash to become a hashref and print 1 if $hash; will print 1. exists takes a hash element, and you can't have a hash element without a hash! :)

Re: Testing a key creates a hash
by davido (Cardinal) on Aug 17, 2005 at 21:54 UTC

    This will eliminate autovivification:

    my $hash = undef; print "shouldn't print\n" if $hash; # still prints nothing if( ref( $hash ) =~ /HASH/ and exists( $hash->{1} ) ) { print "Autovivified\n"; # Won't print; } print "Still shouldn't print.\n";

    If you don't mind $hash suddenly becoming a hashref (despite being an empty hash), you can eliminate the $ref( $hash ) =~ /HASH/ portion of the check. Do see exists.

    You're just getting bitten by autovivification. It's documented behavior.


    Dave

      I don't like your ref-based test (it will give both false positives and false negatives). I'd just be sure to 'use strict' and do 'if $hash && $hash->{1}' instead. Perhaps 'if ref($hash) && $hash->{1}' would also be okay.

      Note that you can also use Data::Diver to avoid autovivification.

      I'd still really like to have a 'no autovivify' pragma... (:

      - tye        

        My point is that the following code will autovivifygenerate a hashref:

        use strict; use warnings; my $href; if( exists( $href->{1} ) ) { print "\$href->{1} = $href->{1}\n"; } print '$href is now a ', ref( $href ), " ref.\n";

        The output will be:

        $href is now a HASH ref.

        The point is that the existance test autoassigns a hash ref to $href in the case that $href was previously undefined.

        My example in my earlier post takes that into consideration, and takes care to not alter the contents of $href even if it was previously undef

        In practice I can't think of a time when I've cared whether a scalar holds an empty hashref or undef, but since we were on the topic of autovivification, I figured it would be advisable to give an example that didn't introduce another possibly confusing behavior.

        I am curious though, how ref will give false positives and negatives, if all it's being used for is to determine whether $href contains a hashref or not? That's exactly what ref does. If ref returns anything other than HASH there's no point proceeding to the exists test. If it returns nothing, once again there's no need to proceed to the exists test. But if it returns HASH, we can proceed to the exists test without worrying that $href will be altered from undef to HASH0xA1234F.

        If I'm missing something I'm open to listen.

        Your 'if ref($hash) && $hash->{1}' would return false negatives if $hash->{1} contains false or undef despite the key existing, and it would autovivify $hash->{1} if $hash contained a hashref, even if it didn't already exist, which doesn't prevent autovivification, I think. ;)

        In the case of if $hash && $hash->{1}, you could get the "Can't coerce xxxxx into hash at ...." messages if $hash contained anything besides the anticipated hash ref.


        Dave

Re: Why does testing a key create a hash?
by brian_d_foy (Abbot) on Aug 17, 2005 at 23:23 UTC

    It's autovivification. To test a hash key, you need to have a hash. Perl creates the hash, then checks the value of the key.

    Depending on what you are doing, you probably want to check if the variable is defined.

    print "Shouldn't print!\n" unless( defined $hash and ... );

    However, if I know something is going to be a hash, I start with a hash.

    my $hash = {};
    --
    brian d foy <brian@stonehenge.com>
Re: Why does testing a key create a hash?
by zentara (Archbishop) on Aug 18, 2005 at 13:33 UTC
    Here is an old post by Merlyn which sheds some light on Autovivification

    I'm not really a human, but I play one on earth. flash japh

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://484615]
Approved by kirbyk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-03-28 12:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found