http://www.perlmonks.org?node_id=800131

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

Q1:

How do you avoid having to test the existence of a hash{key} before testing the existence of its corresponding value?

PREMIS:

The Perlish way to test if a scalar has been set is to do something like:

if ($foo){...}

so ideally the perlish way of testing a value in a hash might be to do something like this:

if ($myHash{"unknown_if_this_key_exists_yet_or_not"}){...}

But the reality is that will not work because an entry for the key automatically gets created in the hash if we try to do that, so we end up having to do something like this instead:

if (exists($myHash{"unknown_if_this_key_exists_yet_or_not"}) and $myHash{"unknown_if_this_key_exists_yet_or_not"}){...}

But that's a lot of typing, and typing isn't very perlish. So how do we avoid having to do this every time?

I thought about using Hash::Util qw{lock_hash unlock_hash) to lock a hash whenever it is not being modified, but programs carp out in the following situation:

if ($myHash{"this_key_does_not_exist"){...}

Again, not very perlish. It would be nice if accessing the hash just returned the value...

So then I considered "use Readonly::Hash"; and then you can do:

Readonly::Hash $myHash => ("key1" = "val1",); $myTempValue = $myHash{"this_key_does_not_exist"};

and the program will not die. But that only works as long as you never have to modify the hash. When that time comes you're in trouble. There does not seem to be any way to make the hash modifiable again once it is made Readonly... Maybe perl monks know of a way?

Finally, I've concluded that the best way to handle this is to just create a separate subroutine that accepts a key as input, checks the existence of both the key and value pair, and then returns the value. But my question to the monks is this: what really is the best way to handle this situation? I'm sure people encounter this problem all the time, and I can't seem to find any documentation for it anywhere. What should the best practice be?

Q2:

When "use strict;" is in effect, how can you avoid having to test the existence of a hash-key before using it to reference an array?

In other words:

How do we avoid having to use the first of the following two lines:

if ($myHash{"unknown_if_this_key_exists_yet_or_not"}){ print "values in list are: @{$myHash{\"unknown_if_this_key_exists_ +yet_or_not\"}}\n"; }

PREMIS:

Really I think it would be much nicer if instead of bombing out, Perl would return an empty list when a list is to be referenced by an undefined value(when using strict). "use warnings;" should be the method of identifying empty references, not "use strict;", and hopefully that will change with perl6, but until then: what should Perl programmers all around the world do?

For one thing, the code above creates a new hash entry if the key didn't already exist, so really the shortest way I can think of to handle it would be something like:

if (exists($myHash{"unknown_if_this_key_exists_yet_or_not"}) and $myHa +sh{"unknown_if_this_key_exists_yet_or_not"}){ print "values in list are: @{$myHash{\"unknown_if_this_key_exists_ +yet_or_not\"}}\n"; }

But I'm sure you agree that's pretty ugly...

So I guess the second question has more to do with Lists than hashes, but a standard for handling these situations should be documented at the very least, hence the reason for starting this blog.

All ideas are welcome...

----------------------------------------------------------------------

Adding the following update three years later (Jan. 2013):

After following this thread and a few others related to autovivification, I have come to believe that the best practice for handling these situations is to avoid them in the first place. Invoking the module "no autovivification" at the top of all your perl code disables autovivification and makes single and multidimensional hashes behave in a more perlish manner. I have been doing this with all my code for the past three years now and have not noticed any negative side affects. I recommend this approach to everyone...

Additionally, for Q2 above, the recommendation to follow the $hash{$ref} with a " || []" when being tested does indeed help when use strict is in place in case there is no value. Ex:

use strict; no autovivification; #<-- include in all programs, all the time! my %myHash =(); print "values in list are: @{$myHash{\"unknown_if_this_key_exists_yet_ +or_not\"} || []}\n";

That particular list was empty...