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

Hi Monks, I am having a nested hash with depth ranging from 4-5 like
VAR1 = {A => { LEVEL1 => { LEVEL1_2 => { LEVEL1_2_3 => { VAL > 'somevalue' } } } } I am using a if statment with defined in a loop, for (my i = 0; i< 3; i++) { if (defined $hash->{A}->{LEVEL2}->{LEVEL2_2) { # do something } elsif (defined $hash->{A}->{LEVEL1}->{LEVEL1_2) { #do something } }
For first loop iteration if returns false, but at the same time it creates an empty slot in a hash with undef value. (I checked it using Data::Dumper in loop to print hash.) so when for loop iterates for 2nd time, empty slot created matches if statment instead of elsif, and execute wrong set of instructions. I am not able to understand why an empty slot is created. somewhere i read there is a issue with use exists with nested (->) structure. Am I hiting the same issue ? I tried without defined, and faced same issue, so unable to understand.
  • Comment on usage of if on nested hash creating empty slot for non existing value
  • Download Code

Replies are listed 'Best First'.
Re: usage of if on nested hash creating empty slot for non existing value
by Anonyrnous Monk (Hermit) on Jan 29, 2011 at 09:36 UTC
    I am not able to understand why an empty slot is created.

    The feature is called "autovivification".

    When you dereference a non-existing element, such as {LEVEL2}->{LEVEL2_2}, the element (the LEVEL2 hashref entry here) is automagically being created as needed.

    #!/usr/bin/perl -w use strict; my $var; if (defined $var->{FOO}->{BAR}) { print "found" } use Data::Dumper; print Dumper $var; __END__ $VAR1 = { 'FOO' => {} };

    Here, in order to check if the entry BAR is defined, a hash(ref) with an entry FOO is being created. The value associated with the entry FOO is created as another hash(ref) which could potentially hold the checked-for entry BAR.

    You might argue this doesn't make sense when just testing for existence or definedness, but that's the way it's currently implemented.  See the threads turned up by the above google search for more in-depth discussion.

Re: usage of if on nested hash creating empty slot for non existing value
by ikegami (Patriarch) on Jan 29, 2011 at 18:26 UTC
    ...->{...} ...->[...]
    is really equivalent to
    ( ... //= {} )->{...} ( ... //= [] )->[...]

    when they're found in an lvalue context (such as the argument of a function like defined).

    You can disable this behaviour for the arguments of defined and exists by adding

    no autovivification;

    Ref: autovivification

Re: usage of if on nested hash creating empty slot for non existing value
by cdarke (Prior) on Jan 29, 2011 at 15:30 UTC
    I don't get the symptoms you describe, although I had to alter your code to get it to compile:
    use strict; use warnings; use Data::Dumper; my $hash; $hash = {A => { LEVEL1 => { LEVEL1_2 => { LEVEL1_2_3 => { VAL => 'somevalue' } } } } }; for (my $i = 0; $i< 3; $i++) { if (defined $hash->{A}->{LEVEL2}->{LEVEL2_2}) { # do something print "if branch\n"; } elsif (defined $hash->{A}->{LEVEL1}->{LEVEL1_2}) { #do something print "elsif branch\n" } else { print "else branch\n" } } print Dumper($hash);
    gives:
    elsif branch elsif branch elsif branch $VAR1 = { 'A' => { 'LEVEL1' => { 'LEVEL1_2' => { 'LEVEL1_2_3' => { 'VA +L' => 'somevalue' } } }, 'LEVEL2' => {} } };
    The key 'LEVEL2' is added by autovivification as described by Anonymous Monk, but not 'LEVEL2_2' as you imply, so it does not go through the 'if'. Could you post some code that compiles and shows the problem you have?
    I'm not sure if this is relevant, but if you want to check for the existence of a key use exists, defined checks for the existence of a value.
Re: usage of if on nested hash creating empty slot for non existing value
by bart (Canon) on Jan 29, 2011 at 16:46 UTC
    if (defined $hash->{A}->{LEVEL2}->{LEVEL2_2}) {
    To prevent autovivification, make this
    if (exists $hash->{A} && exists $hash->{A}->{LEVEL2} && defined $hash- +>{A}->{LEVEL2}->{LEVEL2_2}) {
Re: usage of if on nested hash creating empty slot for non existing value
by biohisham (Priest) on Jan 29, 2011 at 17:10 UTC

    Welcome to the Monastery rakeshrocks

    I checked it using Data::Dumper in loop to print hash
    from How do I post a question effectively? "Paste actual code that reproduces the problem between <code> and </code> tags . State exactly what the problem is. Be precise about the correct behavior / desired output."

    That way, the monks' responses will be more related to finding a solution rather than trying to guess the behavior being described...


    Excellence is an Endeavor of Persistence. A Year-Old Monk :D .