If you don't like the autovivification or simply would like to make sure the code does not accidentally alter a hash the Hash::Util module is for you.
You can lock_hash and later you can unlock_hash if you'd like to make some changes to it.
In this example you can see 3 different actions commented out. Each one would raise an exception if someone tries to call them on a locked hash. After we unlock the hash we can execute those actions again.
I tried this both in perl 5.40 and 5.42.
use strict;
use warnings;
use feature 'say';
use Hash::Util qw(lock_hash unlock_hash);
use Data::Dumper qw(Dumper);
my %person = (
fname => "Foo",
lname => "Bar",
);
lock_hash(%person);
print Dumper \%person;
print "$person{fname} $person{lname}\n";
say "fname exists ", exists $person{fname};
say "language exists ", exists $person{language};
# $person{fname} = "Peti"; # Modification of a read-only value attempted
# delete $person{lname}; # Attempt to delete readonly key 'lname' from a restricted hash
# $person{language} = "Perl"; # Attempt to access disallowed key 'language' in a restricted hash
unlock_hash(%person);
$person{fname} = "Peti"; # Modification of a read-only value attempted
delete $person{lname}; # Attempt to delete readonly key 'lname' from a restricted hash
$person{language} = "Perl"; # Attempt to access disallowed key 'language' in a restricted hash
print Dumper \%person;
$VAR1 = {
'lname' => 'Bar',
'fname' => 'Foo'
};
Foo Bar
fname exists 1
language exists
$VAR1 = {
'language' => 'Perl',
'fname' => 'Peti'
};