in reply to restricting values to a nested datastructure

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;

Replies are listed 'Best First'.
Re^2: restricting values to a nested datastructure
by Marshall (Canon) on Dec 14, 2011 at 12:28 UTC
    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.

Re^2: restricting values to a nested datastructure
by zwon (Abbot) on Dec 14, 2011 at 14:27 UTC
    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.

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

        Not really. Array element maybe defined but false. You can't omit defined as easy as exists.

Re^2: restricting values to a nested datastructure
by Anonymous Monk on Dec 14, 2011 at 12:47 UTC
    Thanks toby it worked.