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

For years, I have been using defined %hash to check for the existence of %hash without creating it. As of Perl 5.11.x this is deprecated for some reason, and causes an annoying deprecation warning. The warning suggests just using %hash, but this auto-vivifies. Unfortunately, I haven't been able to figure out another way to do what I want: check if a hash exists without auto-vivifying its stash slot. Here are things I've tried so far:
main @> keys %test:: undef main @> %{"test::h"} ? 1 : 0 0 main @> keys %test:: 'h' main @> defined %{"test::h2"} ? 1 : 0 0 main @> keys %test:: 'h' main @> *{"test::h3"}{HASH} ? 1 : 0 0 main @> keys %test:: h h3 main @> defined *{"test::h4"}{HASH} ? 1 : 0 0 main @> keys %test:: h h3 h4
Any suggestions?

Edit: After some experimentation, this test seems to do the trick:

exists $test::{"h"} && *{"test::h"}{HASH}
Not too bad.

Replies are listed 'Best First'.
Re: Check for variable without leaving a trace
by Fox (Pilgrim) on Dec 09, 2009 at 10:46 UTC
    make your own solution:
    use Data::Dumper; print Dumper \%hash; print safe_defined(\%hash,"test","test2"); print Dumper \%hash; sub safe_defined { my ($h,@keys) = @_; for(@keys) { return 0 unless defined $h->{$_}; $h = $h->{$_}; } return 1; }


    UPDATE: On a second thought, you should really use exists to test if a key exists on a hash, just change the defined keyword on the sub.
      This isn't what I'm trying to do. I want to check whether a program has used the variable %hash without creating it. You used to be able to do this with defined, but someone thought it would be a good idea to deprecate that. exists $::{hash} can tell you whether one or more of $h, &h, %h, @h is defined, but not which.
        hm, now I get it.
        but I think not even perl can tell that ( $h was used and %h was not, for example)
Re: Check for variable without leaving a trace
by Fox (Pilgrim) on Dec 10, 2009 at 10:07 UTC
    I don't know if you want this to happen or not but it looks like your test detects variables not yet declared:
    BEGIN{print "BEGIN:",grep { $_ eq chaos}keys %::;print"\n"} INIT{print "INIT:",grep { $_ eq chaos}keys %::;print"\n"} END{print "END:",grep { $_ eq chaos}keys %::;print"\n"} print exists $::{"chaos"} && *{"::chaos"}{SCALAR},"\n"; $chaos = 1;
    prints:
    BEGIN: INIT:chaos SCALAR(0xe566e8) END:chaos
Re: Check for variable without leaving a trace
by rowdog (Curate) on Dec 10, 2009 at 15:25 UTC

    The documentation for defined says

    Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate has ever been allocated. This behavior may disappear in future versions of Perl. You should instead use a simple test for size:
    1. if (@an_array) { print "has array elements\n" } 2. if (%a_hash) { print "has hash members\n" }