in reply to Best Multidimensional Hash Practices?

I read as far as your premise. It's wrong. To test if a scalar has been set use:

if (defined $scalar) {

To test if a hash key/value pair exists use:

if (exists $hash{key}) {

To test if the scalar content of a hash value has been set use:

if (defined $hash{key}) {

Those last two steps can be combined:

if (exists $hash{key} && defined $hash{key}) {

and of course you can make the same tests with a multi-dimensional hash:

if (exists $hash{key1}{key2} && defined $hash{key1}{key2}) {

This last example is interesting if key1 didn't exist - it pops into existence. This is a process called autovivification and happens when Perl needs to have a hash or array element in order to write to it or use it to access an element is references.


True laziness is hard work

Replies are listed 'Best First'.
Re^2: Best Multidimensional Hash Practices?
by almut (Canon) on Oct 12, 2009 at 20:06 UTC
    if key1 didn't exist - it pops into existence. This is a process called autovivification

    I always wondered what the design decision behind this autovivification behaviour with mere existence testing had been...  I mean why does Perl not simply do a short-circuit evaluation from left to right, stopping as soon as a hash key does not exist?  In the example, key2 can't possibly exist if there is no hash referenced via key1 at all, because there is not even a key1. So why proceed any further?

      If you do not want the autovivification to happen with exists, try no autovivification 'exists';

      You can even restrict its effects within a lexical scope!

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        IMHO, this should eventually become a core module/pragma...

      Because it isn't exists that triggers autovivication. It is the (implied or explicitely written) -> operator, as was pointed out in the previous thread by DamianKaelGreen.

      Autovivication is exactly the kind of thing that makes this code work:

      use strict; use warnings; my $hashRef; # note how it is undefined at this moment! $hashRef->{cogito} = "ergo sum"; print ref $hashRef, "\n" # Output: HASH # Hey... aint that cool? # But we can go even further! $hashRef->{"somewhere"}->{"deep down"}->{"this"}->{"data structure"} = + "I think, so I exist.";

      Now, that last line isn't a true beauty but there are those cases that you need deep structures like that. And it really wouldn't be Perlish if you had to make each part of it come into existance manually.

        I never said it's the exists itself that autovivifies...  sure it's the dereferencing. And the behaviour is all nice and dandy, if it does make sense to actually access the last element in the chain (and create intermediate structures as required), as is the case with your example where you're assigning a value.  It just doesn't make much sense when there's no real need for complete dereferencing, such as when testing for existence or definedness.

        In other words, why not take the shortcut and just not dereference the entire structure when it's clear right in the beginning that this isn't going to lead to any new conclusions with respect to the existence of the final key?  I mean some special handling could be done for the sake of DWIM, just like it does happen elsewhere in Perl.