in reply to Erm? Bug or not? Weird behaviour in hash / list conversion

With some experimenting, I get strange results if the following conditions are all true: Minimal test cases:
$ perl -le '[%h = (1 .. 4)]' # Fine. $ perl -le '[%h = (1) x 4]' Bizarre copy of ARRAY in anonlist at -e line 1.
Also:
$ perl -le 'print join ".", %h = 1 .. $_ for 1 .. 20' 1 1.2 1.2.3 1.2.3.4 1.2.3.4.5 1.2.3.4.5.6 1.2.3.4.5.6.7 1.2.3.4.5.6.7.8 1.2.3.4.5.6.7.8.9 1.2.3.4.5.6.7.8.9.10 1.2.3.4.5.6.7.8.9.10.11 1.2.3.4.5.6.7.8.9.10.11.12 1.2.3.4.5.6.7.8.9.10.11.12.13 1.2.3.4.5.6.7.8.9.10.11.12.13.14 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20

It's interesting to note that the resulting numbers are still in order - what clearly isn't happening is that the list to join is gotten out of the hash (in keys() order). So I guess that some aliasing into the list on the RHS plays a role, some values are probably munged when inserting them into the hash, causing a collision.

Interesting might also be:

$ perl -le 'print join ".", %h = map {(1, $_)} 1 .. $_ for 1 .. 10' 1.1 1..1.2 1.3.1..1.3 1..1.4.1..1.4 1.5.1..1.5.1..1.5 1..1.6.1..1.6.1..1.6 1.7.1..1.7.1..1.7.1..1.7 1..1.8.1..1.8.1..1.8.1..1.8 1.9.1..1.9.1..1.9.1..1.9.1..1.9 1..1.10.1..1.10.1..1.10.1..1.10.1..1.10

Abigail

Replies are listed 'Best First'.
Re: Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by BrowserUk (Patriarch) on Oct 29, 2003 at 11:36 UTC

    Agreed. Although not all list assignments seem to do it, and you don;t need to be using either join or x or print?

    I'm pretty sure that this is an over zealous optimisation -- reusing an existing stack frame or some such.

    By tying the hash, the problem disappears.

    P:\test>perl sub TIEHASH { return bless {}, 'main'; } sub STORE{ $_[0]->{$_[1]} = $_[2]; } sub FETCH{ $_[0]->{$_[1]} } sub CLEAR{ undef %{$_[0]} } tie %h, 'main'; print %h = ( 1,1,1,1); ^Z 1111

    I tried using B::Concise to isolate a difference between a bizarre result and an expected one.

    Normal

    P:\test>perl -we"print map 1, %h = (1,1,1,1);" Name "main::h" used only once: possible typo at -e line 1. 1111 P:\test>perl -MO=Concise -we"print map 1, %h = (1,1,1,1);" Name "main::h" used only once: possible typo at -e line 1. i <@> leave[t1] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 h <@> print vK ->i 3 <0> pushmark s ->4 f <|> mapwhile(other->g)[t4] lK/1 ->h e <@> mapstart lK/2 ->f 4 <0> pushmark s ->5 - <1> null lK/1 ->5 g <$> const(SPECIAL Null)[t9] s ->f d <2> aassign[t3] lKMS ->e - <1> ex-list lKP ->a 5 <0> pushmark s ->6 6 <$> const(SPECIAL Null)[t5] s ->7 7 <$> const(SPECIAL Null)[t6] s ->8 8 <$> const(SPECIAL Null)[t7] s ->9 9 <$> const(SPECIAL Null)[t8] s ->a - <1> ex-list lK ->d a <0> pushmark s ->b c <1> rv2hv[t2] lKRM*/1 ->d b <#> gv s ->c -e syntax OK

    Bizarre

    P:\test>perl -we"print %h = (1,1,1,1);" Name "main::h" used only once: possible typo at -e line 1. Use of uninitialized value in print at -e line 1. 111 P:\test>perl -MO=Concise -we"print %h = (1,1,1,1);" Name "main::h" used only once: possible typo at -e line 1. e <@> leave[t1] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 d <@> print vK ->e 3 <0> pushmark s ->4 c <2> aassign[t3] lKS ->d - <1> ex-list lKP ->9 4 <0> pushmark s ->5 5 <$> const(SPECIAL Null)[t4] s ->6 6 <$> const(SPECIAL Null)[t5] s ->7 7 <$> const(SPECIAL Null)[t6] s ->8 8 <$> const(SPECIAL Null)[t7] s ->9 - <1> ex-list lK ->c 9 <0> pushmark s ->a b <1> rv2hv[t2] lKRM*/1 ->c a <#> gv s ->b -e syntax OK

    The only difference I can see is entirely due to the map. Exclude that, and the rest is identical.

    So, a bug? If it is, it's been arounf since at least 5.6.1!


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

      The only difference I can see is entirely due to the map. Exclude that, and the rest is identical.
      Well, yeah, but the map makes that you get four new 1's.
      print map 1, 1, 1, undef, 1;
      will print out "1111".
      So, a bug? If it is, it's been arounf since at least 5.6.1!
      I think it's a bug. I think it will be hard to fix. And it has been around since at least 5.005.

      Abigail

        pp_aassign: tmpstr = NEWSV(29,0); if (*relem) sv_setsv(tmpstr,*relem); *(relem++) = tmpstr; didstore = hv_store_ent(hash,sv,tmpstr,0);
        Create new SV, copy stack SV into new SV, set stack element to new SV, store new SV in hash.
        hv_store_ent takes ownership of tmpstr; the second time key SV gets set, the first tempstr is dereffed while still on the stack.

        I don't immediately see why *(relem++) has to be set to tmpstr.
        Other interesting oneliners:
        perl -le 'print join ".", %h = (1,2,1,3,1,4)' 1.4.1..1.4 perl -le 'print join ".", %h = (1,2,1,3,1,[])' 1.ARRAY(0x80fa8cc).1.ARRAY(0x80fa8cc).1.ARRAY(0x80fa8cc)
        And it has been around since at least 5.005.

        5.004_04 (at least.)

        -sauoq
        "My two cents aren't worth a dime.";
        
      Your tied hash example still displays broken-ness:
      perl -e "%h = (1,1,1,1); print %h"
      gives
      11
      not the
      1111
      displayed in your tied hash example.

      rdfield

        Your absolutely right++. Whilst tieing the hash 'fixes' the undefined values problem, it still results in the wrong output.

        Seems pretty clear that there are two bugs that are interacting to produce the bizarre results in the original problem. Tieing the hash bapasses one of them, but the second is still there. Well spotted.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Hooray!