Double Erm?
by Zaxo (Archbishop) on Oct 29, 2003 at 04:58 UTC
|
Trying to puzzle out what the heck is meant by %{{ }} = LIST, I did
$ perl -MO=Deparse -e'print join( "|", %{{ }} = (1)x100 );'
print join('|', %{{};} = (1) x 100);
-e syntax OK
$ perl -e'print join( "|", %{{};} = (1)x100 );'
syntax error at -e line 1, near "%{{};"
Unmatched right curly bracket at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
$
That looks like a borderline syntax error, since perl parses the code to something just as weird, but differently. Or maybe it's an O::Deparse problem.
The behavior you noted goes away if all the hash key slots are different:
$ perl -we'print join( "|", %{{ }} = 1..100 );'
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|2
+7|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|5
+0|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|7
+3|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|9
+6|97|98|99|100$
$ perl -we'print join( "|", %{{ }} = (1,1,2,1,3,1,4,1,5,1) );'
1|1|2|1|3|1|4|1|5|1$
Warnings are on, so the weirdness would show noisily.
| [reply] [d/l] [select] |
|
|
| [reply] [d/l] [select] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by Abigail-II (Bishop) on Oct 29, 2003 at 10:49 UTC
|
With some experimenting, I get strange results if the following conditions are all true:
- There is a hash assignment in list context.
- There's a duplicate key on the RHS of the assignment.
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 | [reply] [d/l] [select] |
|
|
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!
| [reply] [d/l] [select] |
|
|
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 | [reply] [d/l] |
|
|
|
|
|
|
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.
| [reply] [d/l] [select] |
|
|
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by sauoq (Abbot) on Oct 29, 2003 at 05:36 UTC
|
$ perl -le 'print for %h = (1,1,1,1);'
1
1
1
It definitely has something to do with the result of the hash assignment with duplicate keys being interpreted as a list last.
$ perl -le 'print join ".", @a = %h = (1,1,1,1);'
1.1.1.1
Seems to fix it, but
$ perl -le 'print join ".", %h = @a = (1,1,1,1);'
1..1.1
breaks it again.
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] [select] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by Roger (Parson) on Oct 29, 2003 at 04:53 UTC
|
Here is my attempt to explain part of what is happening - in the the code below:
print join( '|', %{{ }} = (1)x100 );
{ } creates a reference to an empty anonymous hash
%{ { } } is the name of the dereferenced anonymous hash.
%{{ }} = (1) x 100 assigns 50 hash entries to the anonymous hash, before it's values are printed.
In fact, I can do the following:
use strict;
print join '|', %{{ 'X' => 1, 'Y' => 1 }} = (1)x100;
as long as the what's inside the anonymous hash forms a legal hash, which is an empty hash in your case.
I am still scratching my head trying to figure out the %hash = (1)x100 part...
It seems
my %x;
my @x = (1) x 100;
print join '|', %x = @x;
produces the same result...
| [reply] [d/l] [select] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by Mr. Muskrat (Canon) on Oct 29, 2003 at 04:48 UTC
|
C:\Documents and Settings\Administrator\Desktop>perl -MO=Deparse -e"pr
+int join('|', %{{ }} = (1)x100 );"
print join('|', %{{};} = (1) x 100);
-e syntax OK
C:\Documents and Settings\Administrator\Desktop>perl -MData::Dumper -e
+ "print Dumper( %{{ }} = (1) x 100);"
Bizarre copy of ARRAY in anonlist at C:/Perl/lib/Data/Dumper.pm line 4
+45.
The conversion from list to hash is confusing things? | [reply] [d/l] [select] |
|
|
Better yet... it appears to be entirely tied to the context of the hash-assignment operation, in a totally bizzare way:
[me@host]$ perl -e '$x = [%y = (1,2,1,2)];'
Bizarre copy of ARRAY in anonlist at -e line 1.
[me@host]$ perl -e '%y = (1,2,1,2); $x = [%y];'
[me@host]$
------------
:Wq
Not an editor command: Wq
| [reply] [d/l] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by rdfield (Priest) on Oct 29, 2003 at 09:50 UTC
|
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).
| [reply] [d/l] [select] |
|
|
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!
| [reply] [d/l] [select] |
|
|
$ 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.";
| [reply] [d/l] [select] |
|
|
"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).
| [reply] [d/l] [select] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by shenme (Priest) on Oct 29, 2003 at 04:33 UTC
|
DB<1> print join( '|', %{{ }} = (1,2,1,4,1,6,1,8) );
DB<2> 1||1|8|1||1|8
but otherwise I'm mystified too | [reply] [d/l] |
Re: Erm? Bug or not? Weird behaviour in hash / list conversion
by Qtax (Initiate) on Oct 29, 2003 at 17:18 UTC
|
This side of the bug has a nice effect too:
perl -le "$,='-'; @a=%h=(a=>1, a=>2); print @a"
a-a-a-2
Did anyone notice this?
So having an @a in print @a = %h=(1,1,1,1); wont fix it really. | [reply] [d/l] [select] |