... Perl certainly isn't doing what I mean... what's the rationale behind it?
Think a little harder about what you are asking for here, and see if you can come up with a sensible rationale for that. Here's a hint:
use strict;
my %HoH;
# case 1:
{
my $uid = 666;
my $host = "foo.bar";
$HoH{$uid}{$host} = "hold onto this value";
}
# what I meant there was: please autovivify $HoH{$uid}
# and set its value to be an anon.hash ref
# case 2:
{
my $uid = "something_unexpected_or_possibly_undef";
my $host = "who_cares_what_value_is_assigned_if_any";
if ( exists( $HoH{$uid}{$host} )) {
do_something_appropriate();
}
}
# what I meant there was: please do not autovivify $HoH{$uid}; ins
+tead,
# do a separate check of hash-key existence for each level of hash
+ nesting
The "exists()" function would have to be the only one that treats dereferencing syntax in this more complicated manner, otherwise perl would not be able to do what you mean in the simple assignment usage. I'm really not familiar with how "exists()" is currently implemented, but I have a hunch that the only way it could be given this special behavior would be to have special operations at compile time that would rewrite your simple expression for you, creating the multi-stage test for hash key existence, which as you already know would need to be done. (And it would have to do the right thing for all variations and depths of dereferencing syntax -- ooh! a source-code filter that creates a recursive function... that sounds like fun!)
Would it be a good idea to make the "exists()" function actually work as a source-code filter at compile time? Food for thought (if you happen to like eating glass shards or sharp metal objects).
As others have pointed out, the problem is not with the "exists()" function, but rather with the process of dereferencing a hash structure. If perl simply refused to autovivify upper/outer hash keys in an HoH(oH...) structure, there would be much less need for using "exists()" (and no need to make it "special" in its treatment of dereferencing). Would you like to take away the ability to autovivify "upper/outer" hash keys in assignment statements? (If that's your preference, I think a lot of perl users would disagree.)
If you are having trouble with this repeatedly, you might want to make up your own version of "exists()" as a module -- but the calling syntax would have to be different... Maybe something like this?
use strict;
use warnings;
my %HoH;
if ( Exists( \%HoH, "foo", "bar", "baz" )) {
warn "Something is very strange\n";
}
print scalar keys %HoH, "\n";
$HoH{foo} = { bar => { baz => "okay" }};
if ( Exists( \%HoH, "foo", "bar", "baz" ) and !Exists( \%HoH, "oops",
+"uhoh" )) {
print "All is well\n";
}
print scalar keys %HoH, "\n";
# the following sub would actually be in a module:
sub Exists
{
my ( $href, $topkey, @subkeys ) = @_;
return unless ( ref( $href ) eq 'HASH' );
my $result = 0;
if ( exists( $$href{$topkey} )) {
$result = ( ref( $$href{$topkey} ) eq 'HASH' and @subkeys ) ?
+
Exists( $$href{$topkey}, @subkeys ) : 1;
}
return $result;
}
(updated to fix a misplaced paren, and to add checks on the $href and @subkeys parameters)
Others could probably write that to be more elegant/compact, but it does what you want to do without violence to a long-established convention. |