* Update: * Sinan points out that my cautious approach to hash element creation is dated and not an issue on newer Perls. I've edited my post below, and added some new thoughts on the matter.
The problem with just testing for truth is that you can modify the hash with thecrufty old version of Perl that I learnt on. This code is safe with Perl 5.8:
my %foo = ();
if( $foo{bar} ) {
print "never happens";
}
print keys %foo;
This is the bad part of the mixed blessing of auto-vivification (over all I like auto-viv, but this is where it hurts).
In many situations, this is no big deal. But it is a potential issue to be aware of. I address this in my code by locking any hash that must remain unmodified.
In practice I either wind up always doing an exists test before a boolean test as well.
if( exists $foo{bar} and $foo{bar} ) {
# hash is not modified due to short circuit
}
The same kind of alteration of data structures can occur with arrays. If you access $foo[2000]
, then the array will be extended. So it can be a good idea to test for existence before you accidentally extend an array. In practice this has been much less of an issue than the corresponding hash behavior. <-- The irony here is that you can
only use exists on an array on perls 5.6 and newer, where presumably this problem has been fixed.
If I need to go digging into data structures, I use Data::Diver. It automatically checks existence at each level in the structure to prevent accidental alteration of your data structure.
The most important thing is to be consistent within each script/program. The easiest way to run into problems is to test for existence here, but truth there. Especially if you are accessing the same hash for both sets of tests.
Final thoughts on my update regarding autovivification: A flurry of research showed several things. I should have tested my code before posting--by failing to do so, I spread misinformation, which I apologize for. I also discovered that there are still some sneaky issues with autovivification lingering--enough that there is an open todo item to make things right. So, while it may be wrong-headed, old-fashioned and dumb, I will continue to explicitly take steps to control autovivification and restrict it to occurring only when I want it to occur. FWIW, autovivification is a great thing when it works. I think special casing if
to prevent autoviv is the right thing to do--it gets rid of the need for a lot of extra code, but I wish I could find some docs that detailed that behavior.