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

Preventing autovivification while accessing value

by naikonta (Curate)
on Jan 28, 2008 at 14:44 UTC ( #664688=perlmeditation: print w/ replies, xml ) Need Help??

I work a lot with complex data structures. When I need to access a value at some depth nested keys which not guaranteed to exist, I have to write,
sub somefunc { my($self, $context) = @_; return 1 # assumed just OK, but no further processing unless $self->{config}{key1} && $self->{config}{key1}{context} && $self->{config}{key1}{context}{$context} && $self->{config}{key1}{context}{$context}{form}; my $form = $self->{config}{key1}{context}{$context}{form}; # I can work with $form ... }
in order to avoid autovivification. But I'm getting tired to do that in all over the file, for every Perl file I work on, with distinct CDSes. Once I thought that I might need to restructure my data, but it wasn't possible to do so and it's still not possilbe to restructure now. So I come up with this little tool after doing some searching with Super Search and CPAN without satisfying result.
sub is_hash { my($hash, @keys) = @_; return unless defined $hash && ref($hash) eq 'HASH'; return $hash unless @keys; my $yes; for (@keys) { $yes = undef, last unless ref $hash eq 'HASH' && %{ $hash }; $yes = undef, last unless exists $hash->{$_} && defined $hash->{$_}; $yes = 1; $hash = $hash->{$_}; } return $yes ? $hash : $yes; }
Now I can write,
return 1 unless my $form = is_hash($self->{config}, 'key1', 'context', $conte +xt, 'form');
It's enough for my needs now. It can be extended further to also allow array references in the middle of the chain,
$somedata, $key1, $key2, $idx3, $key4 ....;

Or, to let us specify certain ref type (including non-ref) we want so it terminates if the ref type mismatches,

my $wanted = 'CODE'; # if key3 has a value but not a CODE ref, it croaks my $code = thefunc($somedata, $wanted, 'key1', 'key2', 'key3'); $code->(@someargs);

So, if you were on my shoes, was it worth for you?


Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Comment on Preventing autovivification while accessing value
Select or Download Code
Re: Preventing autovivification while accessing value
by lidden (Deacon) on Jan 28, 2008 at 15:06 UTC
    Data::Diver

    From its documentation:
    Dive() absolutely refuses to autovivify anything. If you give any 'key' that would require autovivification (or would cause an error or warning), then an empty list is returned.

      Very nice! Thanks lidden :-)

      I have a test script for is_hash() subroutine, the test fails (on purpose) on the latest (17th) test. As soon as I read your reply, I stopped my search on the list resulted from i /^data::/, and run install Data::Diver. I then copied my test script (cp autovivification.pl data-diver.pl), and adjusted some lines. I run both test scripts in sequence to find exactly the same result.

      1..17 ok 1 - id_2 is not supposed to exist ok 2 - no autovivication for id_2 ..... not ok 17 - Since when we have a phone? Oh wait, autovivication is her +e! # Failed test 'Since when we have a phone? Oh wait, autovivication i +s here!' # at autovivification.pl line 117. # Looks like you failed 1 test of 17.
      And here is the 17th test (there's no 'phones' in 'home'),
      print "Hey, we have a fax machine at home!\n" # can't happen if $cds{id_1}{address}{home}{phones}{fax}; ok(!exists $cds{id_1}{address}{home}{phones}, 'Since when we have a phone? Oh wait, autovivication is here!');
      So at least I know it's worth not only for me. And tye has provided a much better solution.

      I got some warning lines when installing....

      t/base....Pseudo-hashes are deprecated at /.../.cpan/build/Data-Diver- +1.0101-Sa9fgP/blib/lib/Data/Diver.pm line 140. Pseudo-hashes are deprecated at /.../.cpan/build/Data-Diver-1.0101-Sa9 +fgP/blib/lib/Data/Diver.pm line 131. Pseudo-hashes are deprecated at /.../.cpan/build/Data-Diver-1.0101-Sa9 +fgP/blib/lib/Data/Diver.pm line 140.

      Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Re: Preventing autovivification while accessing value (Hash::NoVivify)
by lodin (Hermit) on Jan 28, 2008 at 21:26 UTC

    There's also Hash::NoVivify which simply exports Exists and Defined that takes a hashref and a list of keys.

    lodin

Re: Preventing autovivification while accessing value
by Herkum (Parson) on Jan 28, 2008 at 22:57 UTC

    I would suggest that you change your approach of relying upon deeply nested hashes. I can be a source of many headaches and unclear code.

      If the data is best represented that way, why not?

      When you have a data structure that is by itself simpler, but doesn't represent your data very well, things can become more complicated than if you just the best fitting data structure in the first place - even if it's deeply nested.

        He is solving one problem by trying to directly accessing the data, and then causing another problem because he has to deal with autovivification.

        The code becomes larger and harder to understand. I am also willing to bet that this sort of 'check' would be used in more than one place in his program. It should be abstracted out as method and named so that it makes senses in the context that it is being used.

        Another reason to avoid directly accessing deeply nested hashes is when you need to change the data structure. If you are accessing values directly, you end up changing a lot of code to use the new data structure. If it is hidden behind a method, then you only need to change the method to fix the program as a whole.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://664688]
Approved by lidden
Front-paged by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (6)
As of 2014-09-18 00:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (101 votes), past polls