tags:

views:

57

answers:

1

In continue to the discussion here, I'm havind some trouble with lock_hash_recurse as illustrated below:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Hash::Util qw (lock_keys);

my $hashref = {A=>1, B=>{CC=>22, DD=>33}};

lock_keys(%{$hashref}); # this is OK
Hash::Util::lock_hash_recurse(%{$hashref}); # this fails: "Use of uninitialized value in string eq at /usr/lib/perl/5.10/Hash/Util.pm line 153."

From what I can tell, reftype returns undef... is that a bug in lock_hash_recurse (maybe that's why it isn't exported?...)

+6  A: 

It is a bug in Hash::Util. The code says:

sub lock_hashref_recurse {
    my $hash = shift;

    lock_ref_keys($hash);
    foreach my $value (values %$hash) {
        if (reftype($value); eq 'HASH') {
            lock_hashref_recurse($value);
        }
        Internals::SvREADONLY($value,1);
    }
    return $hash
}

but should be:

sub lock_hashref_recurse {
    my $hash = shift;

    lock_ref_keys($hash);
    foreach my $value (values %$hash) {
        my $type = reftype($value);
        if (defined $type and $type eq 'HASH') {
            lock_hashref_recurse($value);
        }
        Internals::SvREADONLY($value,1);
    }
    return $hash
}

The problem is that Scalar::Util::reftype returns undef, not an empty string. A patch has been sent to p5p. It doesn't look like Hash::Util is a dual-life (in core and CPAN) module, so you would have to upgrade to a version of Perl 5 with it fixed. I would suggest either patching the code yourself or writing your own version.

If you write your own version, do not use Internals::SvREADONLY (user level stuff shouldn't use the stuff in the Internals package). Use the Readonly::XS module instead.

Chas. Owens
+1 Thanks. Is there a way to quickly fix that? contact the author or something? I don't want to start my own version...
David B
It looks like it is in the core and not dual-lifed, so reporting it to p5p is all we can do. If you want a fix on the version of Perl you are using, you will have to modify it yourself. Another possibility would be to make `Hash::Util` dual-lifed. I will bring this up on p5p.
Chas. Owens
Whoops, it looks like this was already fixed in [blead](http://perl5.git.perl.org/perl.git/commitdiff/1e6ffe563afa06bebdef40d37cf4bdae8ac5f14d), but it didn't make it into Perl 12.2. You could just apply the same patch to your version.
Chas. Owens
Having this module dual-lifed would be very welcome; I'm stuck on 5.8.8 at $work and the recurse functions aren't available in this version.
Ether
I'd recommend using my module Const::Fast instead of Readonly::XS, if only because the latter actively resists being used directly. Actually it might do what you were trying in the first place, unless you want to be able to 'unlock' it later.
Leon Timmermans
@Ether you could add your voice to the p5p email.
Chas. Owens
@Leon Timmermans I wonder why you recommend that module. I may have to switch.
Chas. Owens
@Chas: See http://blogs.perl.org/users/leon_timmermans/2010/08/yet-another-readonly-module.html. Readonly is a buggy mess. Readonly::XS is nothing more than a reimplementation of Internals::SvREADONLY.
Leon Timmermans
Guys, my aim is just to make sure I don't try to **read** non-existing keys in a deep hash (hash of hashes). I do need to be able to add new keys (aka unlock). I'm not sure what `blead` means. I originally installed perl v5.10.1 using `git`, but now I think I'll start using `perlbrew`. So what should I do to get this to work?
David B
In that case I don't think there's an easy solution. It can be solved using ties and maybe using magic.
Leon Timmermans
@David B `blead` is always the development branch of Perl 5. Dev releases like [Perl 5.13.4](http://search.cpan.org/dist/perl-5.13.4) come out of `blead`. Some changes to `blead` get back ported to maintenance releases like [Perl 5.12.2](http://search.cpan.org/dist/perl-5.12.2). The easiest way to get it to work is to make the same change that is in `blead`. Just add `no warnings 'uninitialized';` after the `use warnings;` in `Hash::Util`. It sucks, but it is your best choice at this point.
Chas. Owens
@Leon Timmermans I suggested `Readonly::XS` because it is a reimplementation of `Internals::SvREADONLY` (which is what `Hash::Util` uses to lock the keys). I said "I wonder why you recommend that module." because I saw you wrote it. I do intend on looking into it.
Chas. Owens
@Chas. Owens. Thanks. I manually edited `/usr/lib/perl/5.10/Hash/Util.pm`. I wonder if I'll have any problems (conflicts?) when I'll try to update my perl version in the future.
David B
@David B Nope, the upgrade will go in `/usr/lib/perl/5.12` or whatever the version is, so you are safe.
Chas. Owens