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

Perhaps you're asking the wrong question:
perl -MData::Dumper -e "for (1 .. 6){print join('.',%h = (1) x $_) . \ +"\n\";print Dumper(\%h)}"
results in the already observed behaviour
1 $VAR1 = { '1' => undef }; 1.1 $VAR1 = { '1' => 1 }; 1..1 $VAR1 = { '1' => undef }; 1..1.1 $VAR1 = { '1' => 1 }; 1..1..1 $VAR1 = { '1' => undef }; 1.1.1..1.1 $VAR1 = { '1' => 1 };
whereas
perl -MData::Dumper -e "for (1 .. 6){%h=(1) x $_;print join('.',%h ) . + \"\n\";print Dumper(\%h)}"
results in
1. $VAR1 = { '1' => undef }; 1.1 $VAR1 = { '1' => 1 }; 1. $VAR1 = { '1' => undef }; 1.1 $VAR1 = { '1' => 1 }; 1. $VAR1 = { '1' => undef }; 1.1 $VAR1 = { '1' => 1 }
which is correct. The question would seem to me to be "why is the 'x' operator propogating to the join?". My guess is that the join is executed for every iteration of the "x", i.e. every time the assignment is triggered %h is updated and the join is executed. (BTW, the undef values are correct and to be expected - see the Dumper results above).

rdfield

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 10:31 UTC
    (BTW, the undef values are correct and to be expected...

    I'm not sure how you reach that conclusion? When you assign an even sized list to a hash, every other value starting with the first is a key, and the next is the value assigned to that key.

    perl -e"%h = (1=>2, 2=>4, 5=>6, 7=>8, 9=>10); $,='-'; print %h;" 1-2-7-8-9-10-2-4-5-6
    If the keys are all the same, then then hash should end up with a single key, with the value of the last item in the list.
    perl -e"%h = (1=>2, 1=>4, 1=>6, 1=>8, 1=>10); $,='-'; print %h;" 1-10

    As you can see, I've eliminated both the join and the X from the equation, but still...

    P:\test>perl -e"$,='-'; print %h = (1,1,1,1,1,1,1,1,1,1);" 1-1-1--1-1-1--1-1

    If I do

    perl -e"$s = 'fred'; print $s;" fred perl -e"print $s = 'fred';" fred perl -e"$,='-'; @a=(1,1,1,1,1,1,1,1,1,1); print @a;" 1-1-1-1-1-1-1-1-1-1 perl -e"$,='-'; print @a=(1,1,1,1,1,1,1,1,1,1);" 1-1-1-1-1-1-1-1-1-1

    It doesn't matter whether I assign then print or print the assignment, the results are the same. With a hash the results are different.

    The real kicker is that after the print assignment, the hash ends up correct.

    perl -MData::Dumper -le"$,='-'; print %h = (1,1,1,1,1,1,1,1,1,1); prin +t Dumper \%h;" 1-1-1--1-1-1--1-1 $VAR1 = { '1' => 1 };

    It's only the results of printing the assignment that is in error...at least that I've so far discovered.


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

      It's only the results of printing the assignment that is in error...at least that I've so far discovered.

      Well, it doesn't have anything to do with the print() really. This avoids printing it directly:

      $ perl -le '$_ = join "-", %h = (1,2,3,4,1,2,3,4); print "yes" if /--/ +' yes

      By the way, I've noticed that map seems to make the problem go away (as does assigning to an array) but grep, reverse, and sort don't:

      map { $_ } %h = ( 1,1, 1,1 ); # no undefined values. grep { 1 } %h = ( 1,1, 1,1 ); # undefs occur. sort %h = ( 1,1, 1,1 ); # undefs occur. reverse %h = ( 1,1, 1,1 ); # undefs occur.

      -sauoq
      "My two cents aren't worth a dime.";
      
      Sorry, BrowserUk, looks like I missed detailing a step in my reasoning: the list to array assignment seems to happen in one "go", so the contents on the LHS of the assignment would only be printed once, whereas coercing a list to a hash appears result in the LHS being updated for every element of the list, and the assignment propogating before it is complete resulting in too many values being printed/joined.

      From my observataions it would seem that the following is being printed: for even numbers of pairs (4 elements, 8 element, 12 elements):

      "1--1-1" x (elements/4)
      (ie the print is call twice, once for key 1 having value undef, once for key value 1 having value 1) and for odd numbers of pairs (2 elements, 6 elements, 10 elements etc):
      "1-1" . "1--1-1" * floor(elements/4)
      (ie print once where key 1 has value 1, then proceed as previously).

      rdfield