in reply to Test if a subhash in a referenced hash exists

if (not exists $coordinates->{$group}{$id}{$stage}{"coords"}) { ...}

(untested)

Perl 6 - links to (nearly) everything that is Perl 6.

Replies are listed 'Best First'.
Re^2: Test if a subhash in a referenced hash exists
by DrHyde (Prior) on May 28, 2010 at 10:43 UTC
    If $group, $id, $stage etc don't exist in $coordinates, then that will auto-vivify them. You need to check the existence of each level in the hash if magically creating them merely by looking at them is a problem for your application. Something like this (ignoring your application's logic for the sake of making my example code clearer):
    if(exists($coordinates->{$group})) { if(exists($coordinates->{$group}->{$id})) { if(exists($coordinates->{$group}->{$id}->{$stage})) { ... } } }
    or to generalise (untested. haven't even tried to compile it) ...
    my $result = do_stuff_in_hash_without_autovivifying( sub { my $hash_to_work_on = shift; # do stuff here }, $coordinates, # initial hash $group, $id, $stage, 'coords' # list of keys to traverse ); sub do_stuff_in_hash_without_autovivifying { my($sub, $hash, @keys) = @_; if(@keys && exists($hash->{$keys[0]}) { return do_stuff_in_hash_without_autovivifying( $sub, $hash->{$keys[0]}, @keys[1 .. $#keys] ); } else { return $sub->($hash); } }
    If you're *really* paranoid about auto-vivification, then you can subvert Tie::Hash::Vivify to turn it into a fatal error instead of silent data corruption:
    use Tie::Hash::Vivify; use Data::Dumper; my $hash = Tie::Hash::Vivify->new(sub { die("No auto-vivifying! Bad programmer! No bikkit!\n".Dumper(\@_)) });
      Another way to prevent autovivification is to use Data::Diver.
      Perl 6 - links to (nearly) everything that is Perl 6.
      Thanks for pointing out that autovivificated hash parts stay around. Reading about autovivification I always thought that those parts would appear on the fly and be gone again after they have been looked at. Since I actually might test hashes several times, I will be on the outlook for this situation.
Re^2: Test if a subhash in a referenced hash exists
by Henri (Novice) on May 28, 2010 at 10:22 UTC
    Moritz, your reply helped me find the problem. After your suggestion did not work either I rechecked the subroutine and found that I had not passed $coordinates into it. Doing so, now your suggestion and my original line both work. Also, I thought about exist, defined and true and think I should use exist, because it is a prerequisite to defined and true. Thanks a lot for your help! Henri

      ...but note that exists does not test what you asked for in the subject line, i.e. if a subhash exists — it just tests whether the respective hash key exists, or more precisely, whether the respective hash element has ever been initialized (with whatever value, including undef).

      $data->{foo} = ""; if ( exists $data->{foo} ) { print $data->{foo}{bar}; # 'Can't use string ("") as a HASH ref +...' }

      or with undef as value (in which case the missing hash would be autovivfied)

      $data->{foo} = undef; if ( exists $data->{foo} ) { print $data->{foo}{bar}; # 'Use of uninitialized value in print +...' }
        If I understand you right, with “exits” I am testing if keys at the top level of the anonymous subhash exist. If I wanted to test if the hash reference exists I would need to use “ref”. Correct?