KANAKADANDI has asked for the wisdom of the Perl Monks concerning the following question:

Hello Experts, We recently upgraded from Perl 5.8.8 to Perl 5.16.3. We started seeing strange issues with hash dereferencing issues. below script use to work fine in 5.8.8 and is causing issues in 5.16.3. we have a number scripts which use below kind of notation, is there anyway to make the below script to work by changing some perl generic settings rather than changing the scripts??

#!/usr/bin/env perl use strict; use Data::Dumper; my %lHash; $lHash{'a'} = 1; $lHash{'b'} = 2; my $lHashRef = \%lHash; my $lValue1 = $lHashRef->{'a'}; print $lValue1."\n"; print Dumper($lHashRef); print ref($lHashRef) . "\n"; my $lValue = ${%{$lHashRef}}{'a'}; print $lValue."\n"; exit 0;

it gives me...

$ perl deref_test.pl 1 $VAR1 = { 'a' => 1, 'b' => 2 }; HASH Can't use string ("2/8") as a HASH ref while "strict refs" in use at d +eref_test.pl line 14.

i tried using no strict "refs", then the warning goes away but it does not print the hash value. Below is the output from older version of Perl (5.8.8)

$ perl perl_deref.pl 1 1 $VAR1 = { 'a' => 1, 'b' => 2 }; HASH 1

Replies are listed 'Best First'.
Re: hash dereferencing issue with perl 5.16.3
by Athanasius (Cardinal) on May 02, 2015 at 16:03 UTC

    Hello KANAKADANDI, and welcome to the Monastery!

    Consider the following excerpt from the Camel Book (4th Edition, 2012, p. 85):

    When you evaluate a hash variable in scalar context, it returns a true value only if the hash contains any key/value pairs whatsoever. If there are any key/value pairs at all, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash.

    So your error message shows that within the expression ${%{$lHashRef}}{'a'} the sub-expression %{$lHashRef} is being evaluated in scalar context. Like toolic, I looked at index-history but didn’t find anything to account for the change.

    In more modern Perls, you have the following syntactic options for dereferencing the hash reference:

    my $lValue = ${$lHashRef}{'a'}; my $lValue = $$lHashRef{'a'}; my $lValue = $lHashRef->{'a'};

    The arrow (->) syntax is usually the best choice as it requires fewer sigils and makes it visually obvious that the expression on the left of the arrow is a reference.

    ...is there anyway to make the below script to work by changing some perl generic settings rather than changing the scripts??

    Probably not. In any case, changing the syntax of the affected expressions from ${%{$ref}}{key} to $ref->{key} is likely the quickest fix, and will have the by-product of making the code more readable.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      In more modern Perls, you have the following syntactic options for dereferencing the hash reference:
      my $lValue = ${$lHashRef}{'a'}; my $lValue = $$lHashRef{'a'}; my $lValue = $lHashRef->{'a'};

      I never use the first of these so cannot comment on that. However, my recollection of the second and third options is that both were available to use last millennium and probably in any version of Perl5. I'm not sure that these are best described as "more modern" these days and think it would be fair to say that use of this syntax would be perfectly valid in any perl likely to be encountered in production today.

      All this is just for clarity of course and I fully endorse and agree with the rest of your post.

        ${$lHashRef}{'a'} is just the "canonical" version of  $$lHashRef{'a'}. In the former syntax,  $lHashRef can be replaced by any expression that evaluates to a hash reference. In the latter syntax, thorny issues of precedence arise if  $lHashRef is replaced by anything other than another scalar hash reference.

        c:\@Work\Perl\monks>perl -wMstrict -le "my $s = undef; my $t = 0; my $u = { qw(a aye b bee) }; ;; print ${ $s || $t || $u }{a}; " aye


        Give a man a fish:  <%-(-(-(-<

Re: hash dereferencing issue with perl 5.16.3
by AnomalousMonk (Archbishop) on May 02, 2015 at 16:09 UTC

    Further to toolic's post, the change seems to have occurred between 5.8.9 and 5.10.1.

    c:\@Work\Perl>perl -wMstrict -le "print qq{perl version $]}; ;; my %h = qw(a aye b bee); my $hr = \%h; ;; print ${ %{$hr} }{a}; print ${ %h }{b}; " perl version 5.008009 aye bee c:\@Work\Perl>perl -wMstrict -le "print qq{perl version $]}; ;; my %h = qw(a aye b bee); my $hr = \%h; ;; print ${ %{$hr} }{a}; print ${ %h }{b}; " perl version 5.010001 Can't use string ("2/8") as a HASH ref while "strict refs" in use at - +e line 1.
    Checking perl5100delta and perl5101delta reveals no explanation for the change.

    Update: Note that similar syntax works/doesn't work for arrays:

    c:\@Work\Perl>perl -wMstrict -le "print qq{perl version $]}; ;; my @ra = qw(zero one two); my $ar = \@ra; ;; print ${ @ra }[1]; print ${ @$ar }[2]; " perl version 5.008009 one two c:\@Work\Perl>perl -wMstrict -le "print qq{perl version $]}; ;; my @ra = qw(zero one two); my $ar = \@ra; ;; print ${ @ra }[1]; print ${ @$ar }[2]; " perl version 5.010001 Can't use string ("3") as an ARRAY ref while "strict refs" in use at - +e line 1.


    Give a man a fish:  <%-(-(-(-<

      thanks a lot for the answers. So i would take it as there is no settings that would enable me to work with my existing Perl scripts without changing them. I would appreciate if someone could suggest me if there is an easy to identify the programs which have these symbolic references. I appreciate your help.

        As far as identifying them goes, you could grep your files for ${%{$ . That sequence of characters isn't likely to show up anywhere else except in these constructs.

        Automating a change would be more tricky, but could probably be done. Something like this which you could filter all problem files through:

        #!/usr/bin/env perl use strict; use warnings; while(<DATA>){ print "before: $_";; s|\${%{\$(\w+)}}{'(\w+)'}|\$${1}->{'$2'}|g; print " after: $_";; } __DATA__ my $lValue = ${%{$lHashRef}}{'a'};

        That might not work on all your variable names or if some are formatted a bit differently, but it could be a start.

        Aaron B.
        Available for small or large Perl jobs and *nix system administration; see my home node.

        thanks a lot for the answers. So i would take it as there is no settings that would enable me to work with my existing Perl scripts without changing them. I would appreciate if someone could suggest me if there is an easy to identify the programs which have these symbolic references. I appreciate your help.

        See references quick reference and use the syntax that is documented to be valid, all other syntax isn't even if it happened to work on somehow at sometime

        suggest me if there is an easy to identify the programs which have these symbolic references.
        Very easy: just run your tests. You do have test suites with high coverage, right? :)
Re: hash dereferencing issue with perl 5.16.3
by toolic (Bishop) on May 02, 2015 at 15:13 UTC
Re: hash dereferencing issue with perl 5.16.3
by AnomalousMonk (Archbishop) on May 03, 2015 at 04:48 UTC
    @files = sort { lc(${@$a}[0]) cmp lc(${@$b}[0]) } @$refdataarr ;

    I knew I'd seen something like the OPed syntax before in one of the dustier alcoves of this place, although admittedly with array refs. instead of hash refs. Please see "strict" violation on "sort" command with perl 5.10. That thread references the transition from Perl version 5.8 to 5.10, but unfortunately gives no further info as to why the syntax was the way it was or why it changed. The advice is just "don't do that." Bit of a dead end, there. Anyhoo...


    Give a man a fish:  <%-(-(-(-<

Re: hash dereferencing issue with perl 5.16.3
by Anonymous Monk on May 03, 2015 at 07:45 UTC