<?xml version="1.0" encoding="windows-1252"?>
<node id="664688" title="Preventing autovivification while accessing value" created="2008-01-28 09:44:07" updated="2008-01-28 04:44:07">
<type id="120">
perlmeditation</type>
<author id="607636">
naikonta</author>
<data>
<field name="doctext">
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,

&lt;code&gt;
sub somefunc {
  my($self, $context) = @_;
  return 1 # assumed just OK, but no further processing
    unless $self-&gt;{config}{key1} &amp;&amp;
           $self-&gt;{config}{key1}{context} &amp;&amp;
           $self-&gt;{config}{key1}{context}{$context} &amp;&amp;
           $self-&gt;{config}{key1}{context}{$context}{form};

  my $form = $self-&gt;{config}{key1}{context}{$context}{form};

  # I can work with $form
  ...
}
&lt;/code&gt;

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 [href://?node_id=3989;HIT=autovivi;re=N;node=3989;Wi|Super Search] and [cpan://vivify|CPAN] without satisfying result.

&lt;code&gt;
sub is_hash {
  my($hash, @keys) = @_;
  return unless defined $hash &amp;&amp; ref($hash) eq 'HASH';
  return $hash unless @keys;

  my $yes;
  for (@keys) {
    $yes = undef,
      last unless ref $hash eq 'HASH' &amp;&amp; %{ $hash };

    $yes = undef,
      last unless exists $hash-&gt;{$_} &amp;&amp;
                 defined $hash-&gt;{$_};

     $yes = 1;
     $hash = $hash-&gt;{$_};
  }

  return $yes ? $hash : $yes;
}
&lt;/code&gt;

Now I can write,

&lt;code&gt;
return 1
  unless my $form = is_hash($self-&gt;{config}, 'key1', 'context', $context, 'form');
&lt;/code&gt;

It's enough for my needs now. It can be extended further to also allow array references in the middle of the chain,

&lt;code&gt;
  $somedata, $key1, $key2, $idx3, $key4 ....;
&lt;/code&gt;

&lt;p&gt;Or, to let us specify certain ref type (including non-ref) we want so it terminates if the ref type mismatches,

&lt;code&gt;
  my $wanted = 'CODE';
  # if key3 has a value but not a CODE ref, it croaks
  my $code = thefunc($somedata, $wanted, 'key1', 'key2', 'key3');
  $code-&gt;(@someargs);
&lt;/code&gt;

&lt;p&gt;So, if you were on my shoes, was it worth for you?

&lt;div class="pmsig"&gt;&lt;div class="pmsig-607636"&gt;
&lt;hr size="1" noshade="1"&gt;
&lt;p align="right"&gt;&lt;small&gt;
&lt;i&gt;Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!&lt;/i&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
