So, I declare a hash, and work with four keys:
#!/usr/bin/perl -w
use strict;
my %hash;
$hash{'a'} = "alpha";
$hash{'b'} = "";
$hash{'c'} = undef;
print "a='" . $hash{'a'} . "'\n";
print "b='" . $hash{'b'} . "'\n";
print "c='" . $hash{'c'} . "'\n";
print "d='" . $hash{'d'} . "'\n\n";
print "defined(a)='" . defined($hash{'a'}) . "'\n";
print "defined(b)='" . defined($hash{'b'}) . "'\n";
print "defined(c)='" . defined($hash{'c'}) . "'\n";
print "defined(d)='" . defined($hash{'d'}) . "'\n\n";
print "exists(a)='" . exists($hash{'a'}) . "'\n";
print "exists(b)='" . exists($hash{'b'}) . "'\n";
print "exists(c)='" . exists($hash{'c'}) . "'\n";
print "exists(d)='" . exists($hash{'d'}) . "'\n\n";
print "a is true\n" if($hash{'a'});
print "b is true\n" if($hash{'b'});
print "c is true\n" if($hash{'c'});
print "d is true\n" if($hash{'d'});
so, as we can see from the output of this, a key can be totally undeclared (not exist), can be declared but undefined (equals undef), OR be declared AND defined yet empty (equals an empty string), all in addition to actually having a populated value. and THEN we can look at which ones evaluate to being true :oi know that this is one of those aspects of perl that scares away sooo many newcomers, and its a shame. because even though perl can confuse a 5+ year user like myself so easily, its complexity is exactly what makes it so versatile.
so while many here already understand everything said, perhaps a few newcomers will read this and walk away not so frightened by hashes and keys and values, oh my!
__________
Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
- Terry Pratchett
I think one of the potentially more confusing parts for newcomers is understanding how hash references autovivify. For example:
use strict;
use warnings;
local $\ = "\n";
my %hash;
print '$hash{a} ', ( $hash{a} ) ? "true" : "not true";
print '$hash{a} ', ( defined $hash{a} ) ? "defined" : "not defined";
print '$hash{a} ', ( exists $hash{a} ) ? "exists" : "doesn't exist";
print "";
print '$hash{a}{b} ', ( $hash{a}{b} ) ? "true" : "not true";
print '$hash{a}{b} ', ( defined $hash{a}{b} ) ? "defined" : "not defined";
print '$hash{a}{b} ', ( exists $hash{a}{b} ) ? "exists" : "doesn't exist";
print "";
print '$hash{a} ', ( $hash{a} ) ? "true" : "not true";
print '$hash{a} ', ( defined $hash{a} ) ? "defined" : "not defined";
print '$hash{a} ', ( exists $hash{a} ) ? "exists" : "doesn't exist";
Prints:
$hash{a} not true
$hash{a} not defined
$hash{a} doesn't exist
$hash{a}{b} not true
$hash{a}{b} not defined
$hash{a}{b} doesn't exist
$hash{a} true
$hash{a} defined
$hash{a} exists
Checking for $hash{a}{b} causes $hash{a} to suddenly contain the reference to an anonymous hash that is checked for the 'b'.
-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.
Checking for $hash{a}{b} causes $hash{a} to suddenly contain the reference to an anonymous hash that is checked for the 'b'.And the exception to this is when using [mod://threads::shared]:
Taking references to the elements of shared arrays and hashes does not autovivify the elements, and neither does slicing a shared array/hash over non-existent indices/keys autovivify the elements.Thus, the following results in a runtime error:
use strict;
use warnings;
use threads;
use threads::shared;
my %hash :shared;
print '$hash{a}{b} ', ( exists $hash{a}{b} ) ? "exists" : "doesn't exist";
$hash{'b'} = "";
And:
$hash{'b'} = "0";
Do the same thing in your example.
Maybe including the program output would be helpful, then point out which results you find surprising.
The results of defined() on "" or undef apply to any perl variable, not just hashes, and a hash key existing after being assigned "" or undef shouldn't really be that surprising.
After running this myself, the only outcome that I didn't expect, was that exists $hash{d} returns false after print $hash{d}. I had expected the print to autovivify the d key to contain undef.
After running this myself, the only outcome that I didn't expect, was that exists $hash{d} returns false after print $hash{d}. I had expected the print to autovivify the d key to contain undef.
The thing to remember is that it is not hash values that autovivify -- it is anonymous hash and array references that autovivify. For example, given an undef scalar, you can autovivify the anonymous hash just by coding as if the scalar contained a hash reference:
use strict;
use warnings;
local $\="\n";
my $hr;
print '$hr ', defined $hr ? 'defined' : 'undefined';
print '$hr->{a} ', exists $hr->{a} ? 'exists' : 'doesn\'t exist';
print '$hr ', defined $hr ? 'defined' : 'undefined';
print '$hr is ', $hr;
Prints:
$hr undefined
$hr->{a} doesn't exist
$hr defined
$hr is HASH(0x3d51c0)
-xdg
Code written by xdg and posted on PerlMonks is [http://creativecommons.org/licenses/publicdomain|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.
It's also interesting to note how undefined and null string values are handled as hash keys.
my %hash;
my $a = undef;
my $b = '';
$hash{$a} = 'foo';
print "$hash{$a}\n";
print "$hash{$b}\n";
Of course both these throw a warning.
C:\temp>hash.pl
Use of uninitialized value in hash element at C:\temp\hash.pl line 8.
Use of uninitialized value in hash element at C:\temp\hash.pl line 9.
foo
foo
It turns out I didn't really understand [http://www.sysarch.com/Perl/autoviv.txt|autovivification] as well as I thought I did. Thanks for the node.
TGI says moo
#!/usr/bin/perl
use strict;
use warnings;
no warnings 'uninitialized';
my @array = 1 .. 5;
$\ = "\n";
sub check {
print "array length: " . @array;
use tt;
[% FOR check IN ["exists", "defined", "true", "" ] %]
for my $i ( 0 .. $#array ) {
print "[% check %]([$i]) is " . [% check %]( $array[$i] );
}
[% END %]
no tt;
print;
}
sub true { !!$_[0] }
check;
delete $array[$_] for 2 .. 3; # creates a hole
check;
undef $array[0]; # operates on the slot, not the array
check;
delete $array[-1]; # reduces length
check;
undef @array; # clears the array
check;
@array = 1 .. 3;
check;
This yields:
array length: 5 exists([0]) is 1 exists([1]) is 1 exists([2]) is 1 exists([3]) is 1 exists([4]) is 1 defined([0]) is 1 defined([1]) is 1 defined([2]) is 1 defined([3]) is 1 defined([4]) is 1 true([0]) is 1 true([1]) is 1 true([2]) is 1 true([3]) is 1 true([4]) is 1 ([0]) is 1 ([1]) is 2 ([2]) is 3 ([3]) is 4 ([4]) is 5 array length: 5 exists([0]) is 1 exists([1]) is 1 exists([2]) is exists([3]) is exists([4]) is 1 defined([0]) is 1 defined([1]) is 1 defined([2]) is defined([3]) is defined([4]) is 1 true([0]) is 1 true([1]) is 1 true([2]) is true([3]) is true([4]) is 1 ([0]) is 1 ([1]) is 2 ([2]) is ([3]) is ([4]) is 5 array length: 5 exists([0]) is 1 exists([1]) is 1 exists([2]) is 1 exists([3]) is 1 exists([4]) is 1 defined([0]) is defined([1]) is 1 defined([2]) is defined([3]) is defined([4]) is 1 true([0]) is true([1]) is 1 true([2]) is true([3]) is true([4]) is 1 ([0]) is ([1]) is 2 ([2]) is ([3]) is ([4]) is 5 array length: 4 exists([0]) is 1 exists([1]) is 1 exists([2]) is 1 exists([3]) is 1 defined([0]) is defined([1]) is 1 defined([2]) is defined([3]) is true([0]) is true([1]) is 1 true([2]) is true([3]) is ([0]) is ([1]) is 2 ([2]) is ([3]) is array length: 0 array length: 3 exists([0]) is 1 exists([1]) is 1 exists([2]) is 1 defined([0]) is 1 defined([1]) is 1 defined([2]) is 1 true([0]) is 1 true([1]) is 1 true([2]) is 1 ([0]) is 1 ([1]) is 2 ([2]) is 3
perlmonks.org content © perlmonks.org and EvanK, fireartist, jdhedden, jwkrahn, nothingmuch, TGI, xdg
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03