Autovivification bit me today

For the first time in more than five years, I got bit by autovivification.  It’s one of those odd quirks of Perl that I’d read about, and heard the problems with but never bumped in to them.

I had put together a chunk of code using a hashref, which differentiated between the hash being undefined and being empty.

My hashref was initialized:

my $hashref = undef;

Code read:

return if exists $hashref->{something};
load_hashref($hashref) unless defined $hashref

See how that isn’t going to work?  I see it now, but it took a few miutes of dinking around with Data::Dumper to figure out what was happening.

The use of $hashref->{something} autovivifies the hash in $hashref to {}, which messes up the undef check below it.

Now I have to decide if I’m going to change the code to check if the hash is empty rather than undef, or if I’m going to stick a “defined $hashref and” before the exists check and short-circuit the exists and autovivification.

Using {} will be more robust, so I should go that way.

How do you tell if a hash is empty, anyway?  keys gives a list, and the list in scalar context is the number of items.

Code is now:

my $hashref = {};
return if exists $hashref->{something};

load_hashref($hashref) unless scalar keys %$hashref;

Thus, nothing will come along and screw up the code by accidentally referring to the hash.

Yay!

Tags:

7 Responses to “Autovivification bit me today”

  1. Pedro Melo says:

    The last line can even be simpler:

    load_hashref($hashref) unless %$hashref;

    Best regards,

  2. matt says:

    you shouldn’t need scalar keys
    my $hashref = {};
    return if exists $hashref->{something};
    load_hashref($hashref) unless %$hashref;

  3. Laufeyjarson says:

    I was following the advice from http://www.perlmonks.org/?node_id=173677 which points out that not all tied hashes behave properly in those situations.

    In my specific case, it would have been fine, but in the general case it might not always work.

  4. lwsitu says:

    you don’t need to use scalar keys, just using a hash in scalar context would work as well

  5. b says:

    I like

    return if $hashref and exists $hashref->{something};

    much better than counting the keys.

  6. Even if you stick with keys, you don’t need scalar.

    But I would add a clause to prevent autovivification instead of permitting an empty hash.

    Note that a normal reference can never be a false value, so you don’t really need defined, just checking for truthiness is fine.

    Bottom line, I’d write:


    return if $hashref and $hashref->{something};
    load_hashref $hashref if not $hashref;

  7. Jeremy Leader says:

    What happens if you’ve already called load_hashref earlier, and it loaded an empty hash? Should you call load_hashref again this time around, or not?

    I think that argues for guarding against autovivification, and in favor of distinguishing between 2 different states:

    $hashref is defined: means load_hashref has already been called, even if it loaded 0 keys

    $hashref is not defined: means load_hashref hasn’t been called yet.

Leave a Reply