Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

keys %{$hash->{$href}} adds $href to the hash if it doesnt exist?

by nikmit (Sexton)
on Nov 17, 2017 at 09:21 UTC ( [id://1203648]=perlquestion: print w/replies, xml ) Need Help??

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

Dear monks,

I came across this behaviour in perl which I find unintuitive, was wondering what the use case scenario for it is or whether I have done something wrong to bring it about...

I had a statement checking for the existence of data like so return 0 unless keys %{$hashref->{$key}} and I failed to realise that $key may not always exist.

I would have expected to see an error if $href->{$key} is undefined and therefore not a reference, but instead $key was just added to the hash.

Example:

#!/usr/bin/perl -w #perl-5.22.3 use strict; my $href = { cat => {milk => 1}, dog => {bone => 1} }; if (keys %{$href->{cow}}) { print "noop\n"; } else { if (exists $href->{cow}) { print "holy cow\n"; } else { print "no cow\n"; } }

This prints 'holy cow'

Replies are listed 'Best First'.
Re: keys %{$hash->{$href}} adds $href to the hash if it doesnt exist?
by Discipulus (Canon) on Nov 17, 2017 at 09:32 UTC

      Care must be used with exists as it will indeed autovivify intermediate hashes:

      use strict; use warnings; use feature 'say'; use Data::Dumper; $Data::Dumper::Sortkeys = $Data::Dumper::Indent = 1; my $href = { cat => { milk => 1 }, dog => { bone => 1 }, }; say exists $href->{'cow'}->{'alfalfa'} ? 'cow' : 'no cow'; say Dumper $href __END__
      Output:
      no cow $VAR1 = { 'cat' => { 'milk' => 1 }, 'cow' => {}, # uh-oh 'dog' => { 'bone' => 1 } };
      So you would have to either use exists on all levels of the structure as haukex suggested:
      use strict; use warnings; use feature 'say'; use Data::Dumper; $Data::Dumper::Sortkeys = $Data::Dumper::Indent = 1; my $href = { cat => { milk => 1 }, dog => { bone => 1 }, }; say exists $href->{'cow'} && exists $href->{'cow'}->{'alfalfa'} ? 'cow' : 'no cow'; say Dumper $href __END__
      Output:
      no cow $VAR1 = { 'cat' => { 'milk' => 1 }, 'dog' => { 'bone' => 1 } };
      ... or use autovivification:
      use strict; use warnings; use feature 'say'; use Data::Dumper; $Data::Dumper::Sortkeys = $Data::Dumper::Indent = 1; my $href = { cat => { milk => 1 }, dog => { bone => 1 }, }; no autovivification; say exists $href->{'cow'}->{'alfalfa'} ? 'cow' : 'no cow'; say Dumper $href __END__
      Output:
      no cow $VAR1 = { 'cat' => { 'milk' => 1 }, 'dog' => { 'bone' => 1 } };
      Note that autovivification.pm has effect lexically:
      use strict; use warnings; use feature 'say'; use Data::Dumper; $Data::Dumper::Sortkeys = $Data::Dumper::Indent = 1; my $href = { cat => { milk => 1 }, dog => { bone => 1 }, }; { no autovivification; say exists $href->{'cow'}->{'alfalfa'} ? 'cow' : 'no cow'; say Dumper $href } say exists $href->{'cow'}->{'alfalfa'} ? 'cow' : 'still no cow'; say Dumper $href; __END__
      no cow $VAR1 = { 'cat' => { 'milk' => 1 }, 'dog' => { 'bone' => 1 } }; still no cow $VAR1 = { 'cat' => { 'milk' => 1 }, 'cow' => {}, # uh-oh 'dog' => { 'bone' => 1 } };


      The way forward always starts with a minimal test.
      Thanks - no autovivification will become a permanent presence for me, next to use strict.
Re: keys %{$hash->{$href}} adds $href to the hash if it doesnt exist?
by haukex (Archbishop) on Nov 17, 2017 at 09:42 UTC

    This is "autovivification" and was just discussed the other day, see the replies in the thread Array dereference in foreach(), including the ones deeper down in the thread.

    Use exists to check if a hash key exists. As described in its documentation, if you have multi-level data structures (hashes of hashes), you need to check every level. Update: Discipulus just updated to show an example.

Re: keys %{$hash->{$href}} adds $href to the hash if it doesnt exist?
by Eily (Monsignor) on Nov 17, 2017 at 10:01 UTC

    FYI, while keys %hash returns the number of keys in scalar context, you can also use the hash itself, the value will be false if the hash is empty and true otherwise (actually 0 when empty, and information on the content otherwise). So if (exists $href->{cow} and %{ $href->{cow} }). Unlike the keys version, scalar %{ $href->{cow} } will not create a new hash (autovivify) if the cow key doesn't exist, but die instead (at least if you forgot to check if the key exists, you'll get an error in the right place).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1203648]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (6)
As of 2024-04-23 11:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found