I recently wrote some code that spent an awful lot of time making decisions and taking branches based on the contents of various entries in a hash-ref. A constant irritating source of bugs was me making typos and trying to read hash entries that didn't exist. After I'd tracked down the first three or four of these hard-to-find bugs I decided to see if I could make it easier on myself.

I found Tie::Hash::Vivify which lets you hook into auto-vivification. The author's intention was apparently to let you automatically populate hash entries when you access them. I subverted it like this:

use Tie::Hash::Vivify; use Carp qw(confess); use Data::Dumper; my $hashref = Tie::Hash::Vivify->new(sub { confess("No auto-vivifying! +\n".Dumper(\@_)) });

so now whenever I try to read a hash entry that doesn't exist, my code dies with a stack trace (so I can tell where the error is) and shows me the parameters that were passed to FETCH (telling me what the error is).

Hurrah!

Replies are listed 'Best First'.
Re: Death to auto-vivification
by clinton (Priest) on Mar 03, 2008 at 12:25 UTC
    You could also check out Data::Diver by tye, for which "Dive() absolutely refuses to autovivify anything".
Re: Death to auto-vivification
by bobf (Monsignor) on Mar 03, 2008 at 19:21 UTC

    You may find Hash::Util or Readonly interesting. I haven't used either but I'm sure other monks could chime in on their pros and cons. A Super Search might point you in the right direction, too.

      I'm a fan of Hash::Util when working with hash-based objects, myself. I tend to use init routines that look like this (to make it impossible to accidentally create a hashkey that's not supposed to be there):
      use Hash::Util qw( lock_keys unlock_keys ); sub init { my $self = shift; my $args = shift; unlock_keys( %{ $self } ); my @attributes = qw( something_or_other another_something ); foreach my $field (@attributes) { $ATTRIBUTES{ $field } = 1; $self->{ $field } = $args->{ $field }; } lock_keys( %{ $self } ); return $self; }