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

Hi All, Please help me to restrict the population of this hash structure. CODE: ===== #!/usr/bin/perl my %a; if (defined $a{'abd'}->[0] ){ print "yes \n"; } use Data::Dumper; print Dumper \%a; RESULT ====== $VAR1 = { 'abd' => [] }; Objective is to restrict automatic creation of this structure on validation.
  • Comment on restricting values to a nested datastructure

Replies are listed 'Best First'.
Re: restricting values to a nested datastructure
by tobyink (Canon) on Dec 14, 2011 at 12:02 UTC

    The word you're looking for is "autovivification".

    You can avoid autovivifying hash and array slots by checking they exist first. Example:

    #!/usr/bin/perl my %a; if (exists $a{'abd'} and exists $a{'abd'}->[0] and defined $a{'abd'}->[0]) { print "yes \n"; } use Data::Dumper; print Dumper \%a;

    An alternative way of doing it would be to use the autovivification module (requires Perl >= 5.8.3). This produces nicer looking code, at the cost of a non-core dependency.

    #!/usr/bin/perl no autovivification; my %a; if (defined $a{'abd'}->[0]) { print "yes \n"; } use Data::Dumper; print Dumper \%a;
      I installed and tested this autovivification critter on my ActiveState Windows machine. Looks like it works just fine. Although I am a bit puzzled why I didn't need a "use Autovivification;" statement. However this does appear to work and in a lexical context as described in the docs.
      #!/usr/bin/perl -w use strict; use Data::Dumper; my %a; { no autovivification 'exists'; if (exists ( $a{'abd'}->[0] ) ) { print "yes \n"; } } print Dumper \%a; if (exists ( $a{'abd'}->[0] ) ) { print "yes \n"; } print Dumper \%a; __END__ $VAR1 = {}; $VAR1 = { 'abd' => [] };

        Perl's no keyword autoloads the module for you.

        use Foo is an abbreviation for:

        BEGIN { require Foo; } Foo->import;

        The counterpart no Foo is an abbreviation for:

        BEGIN { require Foo; } Foo->unimport;

        Because import and unimport are just regular old subs, this means that modules can do their interesting stuff with no instead of use. It's a cute trick, though can confuse people.

      if (exists $a{'abd'} and exists $a{'abd'}->[0] and defined $a{'abd'}->[0])

      There's no need to use exists. You know that $a{abd} is a reference if it exists, so just check if it is true. exists on array elements is deprecated, and doesn't really make much sense. So you can reduce this to:

      if ($a{abd} && defined $a{abd}[0])
        Well if we are going to this way, I would use 'exists' for the hash key and 'defined' for the array element, a personal preference.

        #!/usr/bin/perl -w use strict; use Data::Dumper; my %a; if ( exists $a{'abd'} and defined $a{'abd'}->[0] ) { print "yes\n"} print Dumper \%a; __END__ Prints: $VAR1 = {};
        I prefer the arrow notation instead of $a{abd}[0]

        However, Update: not the same! forgot about 0, zero, Ooops

        if ( $a{'abd'} and $a{'abd'}->[0]) { print "yes\n"}
        is the same.

        Whether each term doesn't "exist" or is not "defined" has the same true/false meaning. To prevent the autovivification, each "level" of the hash has to be tested, starting from the first. As long as that is done, it doesn't matter whether 'exists' or 'defined' is tested for subsequent levels.

      Thanks toby it worked.
Re: restricting values to a nested datastructure
by BrowserUk (Patriarch) on Dec 14, 2011 at 11:20 UTC

    See Hash::Util.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?