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

I have a small curiosal problem. Look at the following:
#!/usr/bin/perl -w my (%hash); my (@keyarr)=(keys (%hash)); if (defined ($hash{$keyarr[0]}})) {print "hash is defined\n";} else {print "hash is undefined\n";}
If the hash is defined the running of the program doesn´t couse any problems, but if the hash is undefied I get the error message: "Use of uniintialised value in hash element". The the whole purpose of the code in a larger concept is to look if the hash is defined, if it is so do A if it is not do B. It should therefore not print error messages if the hash is not defined, becouse it may very well be undefined. Do you have any solution to this small problem?

2006-02-11 Retitled by planetscape, as per Monastery guidelines
Original title: 'Defied vs. undefined'

Replies are listed 'Best First'.
Re: Defined vs. undefined
by xdg (Monsignor) on Feb 10, 2006 at 12:15 UTC

    The real issue you have is that when the hash is empty, @keyarr gets no values from keys %hash. Thus, $keyarr[0] is undefined, causing the warning.

    However, when the hash is not empty, @keyarr has values, so $keyarr[0] is defined and doesn't trigger the warning.

    Add a print statement to show what's in @keyarr and then it may be clearer to you what is happening.

    my (%hash); #my (%hash) = ( foo => 'bar' ); # Try this variation my (@keyarr)=(keys (%hash)); print "keys: '@keyarr'\n"; # Add this line if (defined ($hash{$keyarr[0]})) {print "hash is defined\n";} else {print "hash is undefined\n";}

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      xdg, you're right, but then the question is why one would use a variable that is potentially undefined??
      for this, testing whether the hash has values is better like in muntfish's solution.
      But if you go that route, why don't you directly test if (scalar(%hash)!=0) { ....??
      using a hash in scalar context gives 0 for a empty hash and the number of used entries for a nonempty hash.
      my %hash = (1=>2,3=>4);print "scalarval=".scalar(%hash); => 2/8

      Cheers,
      Rob
        xdg, you're right, but...

        I didn't recommending that approach. I just answered the original question. Sometimes a limited answer is the one that people need in order to make their own discoveries. (See "Baby" Perl versus "Bad" Perl.)

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Defined vs. undefined
by monarch (Priest) on Feb 10, 2006 at 11:39 UTC
    I take it you want to run your program depending on whether the hash %hash has been declared.

    This is harder to do than you think. If you run with use strict; somewhere in your code then the program will not run unless %hash is defined.

    If you run the code without use strict; somewhere in your code then the program will run whether %hash is declared or not. But there lies the next problem: the hash will magically be created the very first time you refer to it. Therefore the mere fact you are trying to access the hash means that it must exist.

    So the only problem you can solve is whether the hash contains anything. If the hash is empty then (@keyarr == 1). Otherwise (@keyarr != 1).

    Update: as muntfish correctly identified (@keyarr == 0) is the test to use.

      To clarify - unlike scalars, arrays and hashes can't be "undefined". They can be empty, which is slightly different.

      monarch, to test for emptiness, you said:

      If the hash is empty then (@keyarr == 1).

      I think you mean 0 not 1:

      my %hash; my @keyarr = keys %hash; print scalar @keyarr;

      prints 0.


      s^^unp(;75N=&9I<V@`ack(u,^;s|\(.+\`|"$`$'\"$&\"\)"|ee;/m.+h/&&print$&
Re: Defined vs. undefined
by kwaping (Priest) on Feb 10, 2006 at 16:17 UTC
    Here's a golfed version of the previous solutions.
    #!/usr/bin/perl use strict; use warnings; my %hash; print %hash ? 'defined' : 'undefined';


    Update: Changed keys %hash to plain old %hash, per swampyankee's post. Duh me!
Re: Defined vs. undefined
by swampyankee (Parson) on Feb 10, 2006 at 19:08 UTC

    You're actually not checking to see if %hash is defined, but only if that specific element of the hash is defined. This is clearly not the same thing.

    Now, as the prior respondents (all of whom have more Perl-dharma than do I) have noted, there are other ways of seeing if the hash is defined.

    One is the obvious if(%hash), as in:

    print "\%hash is defined\n" if(%hash);

    or

    you could try something like

    $defined = keys(%hash);

    My preference is for the first; it looks like it involves less work for Perl. The second looks like it's extracting all the keys so it can count them, and then throws away everything except the count. This seems wasteful.

    emc

    " When in doubt, use brute force." — Ken Thompson