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

I've found an odd bit of behavior when I assign a list to a hash within a subroutine. When the following conditions are met, the resulting hash will not contain all of the keys that were assigned to it.

1) The hash is defined within a subroutine

2) The list assigned to the hash contains a duplicate key

3) The hash is returned out of the subroutine without 'return'.

The following code demonstrates this. The first hash contains all ten keys (one is duplicated) while the second contains only eight keys.

#!/usr/bin/perl use strict; use warnings; my %hash = ( "A" => 1, "B" => 1, "C" => 1, "D" => 1, "E" => 1, "B" => 1, "F" => 1, "G" => 1, "H" => 1, "I" => 1, "J" => 1, ); for my $key (sort(keys(%hash))) { print "$key\n"; } my %hash2 = makesubhash(); print "_"x10,"\n"; for my $key (sort(keys(%hash2))) { print "$key\n"; } sub makesubhash { my %subhash = ( "A" => 1, "B" => 1, "C" => 1, "D" => 1, "E" => 1, "B" => 1, "F" => 1, "G" => 1, "H" => 1, "I" => 1, "J" => 1, ); }
If you remove the duplicate key (B), or explicitly 'return %subhash' the problem will not occur. Normally I use explicit returns all the time, but I stumbled across this and thought it was odd.

Is there a good reason for this behavior? Have I stumbled across a bug in perl?

EDIT: I'm using perl version 5.8.5. I've removed the DateTime module from the code; didn't mean to include it. The output looks like this:

A B C D E F G H I J __________ B C D E F G H I

Replies are listed 'Best First'.
Re: Missing Hash Keys When Hash Created in Sub
by MidLifeXis (Monsignor) on Feb 23, 2015 at 21:25 UTC

    What version of perl are you using? 5.8.8 (msys) / 5.8.9 (AS 826) both exhibit this behavior. 5.18.2 Strawberry does not.

    #!perl use strict; use warnings; my %hash = ( "A" => 1, "B" => 1, "C" => 1, "D" => 1, "E" => 1, "B" => 1, "F" => 1, "G" => 1, "H" => 1, "I" => 1, "J" => 1, ); for my $key (sort(keys(%hash))) { print "$key\n"; } print "_"x10,"\n"; my %hash2 = makesubhash(); for my $key (sort(keys(%hash2))) { print "$key\n"; } sub makesubhash { my %subhash = ( "A" => 1, "B" => 1, "C" => 1, "D" => 1, "E" => 1, "B" => 1, "F" => 1, "G" => 1, "H" => 1, "I" => 1, "J" => 1, ); }

    Perl 5.8.8/5.8.9

    A B C D E F G H I J __________ B C D E F G H I

    Perl 5.18.2

    A B C D E F G H I J __________ A B C D E F G H I J

    --MidLifeXis

      5.8.5
Re: Missing Hash Keys When Hash Created in Sub
by Anonymous Monk on Feb 23, 2015 at 22:35 UTC

    Bisecting shows this bug was fixed by 4596056478d3a as a fix for RT#31865, and the fix was part of the Perl v5.14.0 release:

    When assigning a list with duplicated keys to a hash, the assignment used to return garbage and/or freed values:

    @a = %h = (list with some duplicate keys);

    This has now been fixed.

      Thank you!
Re: Missing Hash Keys When Hash Created in Sub
by LanX (Saint) on Feb 23, 2015 at 23:02 UTC
Re: Missing Hash Keys When Hash Created in Sub
by Anonymous Monk on Feb 23, 2015 at 21:33 UTC

    Looks like a bug... can reproduce something similar on Perl v5.10.1, not v5.20.0 via:

    $ perl -MData::Dump=pp -e 'sub x {my %x=(A=>1,B=>2,B=>3)}; pp {x()}' { "" => "B", "B" => undef }

      I can't decide -- is it more bug or programmer error? ;) Not using return offends my programming sensibilities at some level.

      Dum Spiro Spero
        AnomalousMonk already pointed out that it's a hash bug and not depended on return, but ...

        > Not using return offends my programming sensibilities at some level.

        Many DSL constructs (read "sexy") are based on this "lispy" feature.

        In Ruby it's "super cool", don't wanna see the reaction if e.g. blocks in List::MoreUtils et.al. would require an explicit return.

        As always mixing apples and oranges leads to fruit salad. =)

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)

        PS: Je suis Charlie!

        ... more bug or programmer error?

        Bug. Definite bug. While implicit return is double-plus-unstyleful IMHO, construction of a hash with duplicated keys in list context per LanX's reply is (or ought to be) perfectly well defined and understood.


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

        Heh, I agree. Still, it violates what I know about how subroutine return values are supposed to work.
      Thanks, that appears to be the prevailing wisdom.
Re: Missing Hash Keys When Hash Created in Sub
by roboticus (Chancellor) on Feb 23, 2015 at 21:26 UTC

    Stringer:

    I can't reproduce that behavior. I'm using v5.18.1 and v5.20.1 under MacOsX. What version and OS are you using? Does the behavior require DateTime?

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      5.8.5 RHEL4. DateTime is not required; I've edited out of my code above.
Re: Missing Hash Keys When Hash Created in Sub
by Discipulus (Canon) on Feb 23, 2015 at 21:29 UTC
    your output is different from the following one?
    A B C D E F G H I J __________ A B C D E F G H I J

    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Output looks like this:
      A B C D E F G H I J __________ B C D E F G H I
Re: Missing Hash Keys When Hash Created in Sub
by GotToBTru (Prior) on Feb 23, 2015 at 21:24 UTC

    Perl hashes can't contain duplicate keys.

    Dum Spiro Spero

      It appears from the commentary that the OP understands the behavior of duplicate keys in a hash. The behavior that is being seen is that the first and last key appear (at least when I run it) to disappear.

      --MidLifeXis

        I get the exact same (correct) results running in 5.8.8 for aix and 5.20.1 for Windows.

        Dum Spiro Spero
        This is correct.