Is there a Hash::Util alternative for compound hashes?

198 views Asked by At

I have a compound hashref as follows

my $ch = {
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ... ],
};

Hash::Util::lock_hashref_recurse($ch) does not effectively lock these values..

@{$ch->{k1}}[0]->{k} = 'New value'; is allowed ! How do i lock such a hashref completely ?

5

There are 5 answers

0
Hln On

What about Readonly?

E.g.

use Readonly;
Readonly my %h3 => (
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ],
);
print "old value: '$h3{k1}->[0]->{k}'\n";
$h3{k1}->[0]->{k} = 'New value';
print "new value: '$h3{k1}->[0]->{k}'\n";

gives

old value: '1'
Modification of a read-only value attempted at readonly.pl line 7

Note that %h3 is a hash, not a hashref. Hashrefs don't work well with Readonly:

use Readonly;
Readonly my $h2 => {
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ],
};
print "old value: '$h2->{k1}->[0]->{k}'\n";
$h2->{k1}->[0]->{k} = 'New value';
print "new value: '$h2->{k1}->[0]->{k}'\n";

gives

old value: '1'
new value: 'New value'
0
tobyink On

There is Const::Fast, which is able to make any Perl variable completely read-only.

You won't get the die-on-read behaviour of Hash::Util when you try to read a non-legal key though.

0
Oleg V. Volkov On

Hash::Util itself provides you a low-level function that you can replicate in Perl without XS functionality: i.e. lock_hash / lock_hashref. The rest of functionality you need is a simple hash traversal and can be easily implemented manually. Traverse through nested references while keeping list of visited ones and list of found hashes and then run loop over that found list with lock_hashref.

1
Miguel Prz On

According to the documentation:

This method only recurses into hashes that are referenced by another hash. Thus a Hash of Hashes (HoH) will all be restricted, but a Hash of Arrays of Hashes (HoAoH) will only have the top hash restricted.

And you have a Hash of Arrays of Hashes

0
daxim On
use strictures;
use Hash::Util qw(lock_hash);
use Data::Visitor::Callback qw();

my $ch = {
    k1 => [{k => 1}, {m => 2}],
    k2 => [{l => 90},],
};

Data::Visitor::Callback->new(
    hash => sub {
        lock_hash %{ $_ }; 
        return $_;
    }
)->visit($ch);

$ch->{k1}[0]{k} = 'New value';
__END__
Modification of a read-only value attempted at …