Suppose you have a HUGE application "develoopped" ;) by a big team. Here is a simplified model of the potential disaster that may occur when somebody checks too deep in a data structure. If not possible to disable autovification completely or in scope, how to work around this? Thank you very much :) !!!!
use strict; use warnings;use Data::Dumper;
my $some_ref = {akey=>{deeper=>1}};
print Dumper($some_ref );
if($some_ref->{deep}{doot} == 1){
print 'too deep '.$/;
}
if($some_ref->{deep}){
print 'Already in a deep doot'.$/;
}
print Dumper($some_ref );
This outputs the following:
$VAR1 = {
'akey' => {
'deeper' => 1
}
};
Use of uninitialized value in numeric eq (==) at autovivify_test.pl line 5.
Already in a deep doot
$VAR1 = {
'deep' => {},
'akey' => {
'deeper' => 1
}
};
Yes I know there is a warning, but... it may be too late.
It will help to say that my hashref references a tied HASH.
May be if I implement a good FETCH method which checks for checks deeper in the structure, I will solve easily my problem?
I looked at Tie::StrictHash,Tie::Hash and perltie. Here is simplified version of my solution:
#!/usr/bin/env perl;
#test_tie.pl
package StrictHash;
use strict; use warnings;
use Tie::Hash;
our @ISA = qw(Tie::StdHash);
use Carp;
sub TIEHASH {
my $class = shift;
my $hash = bless {@_}, $class;
return $hash;
}
##========================================================================
## FETCH fails if applied to a member that doesn't exist.
##========================================================================
sub FETCH {
my ($hash, $key) = @_;
Carp::confess "key '$key' does not exist" unless exists $hash->{$key};
return $hash->{$key};
}
##========================================================================
package main;
use strict;use warnings;use Data::Dumper;
#Imagine StrictHash is in ./StrictHash.pm
#use StrictHash;
my %hash;
tie %hash, 'StrictHash', akey => {deeper=>1} ;
my $some_ref =\%hash;
print Dumper($some_ref );
if($some_ref->{deep}{doot} == 1){
print 'too deep '.$/;
}
What I achieved is to touch only one place in the app. Now all Places like if($some_ref->{deep}{doot}) will cause die with stack-trace. So I will easily find them and correct them. And new writings of this kind will NOT be possible. Perl is good for big apps too, you just need to know more ;).
Thank you all! I hope this helps others too.
You might want to use an object instead of the hash (see Moose) or use a strict tied hash. Or you can turn warnings into errors, if you really want to:
use warnings NONFATAL => 'all', FATAL => 'uninitialized';