in reply to question re: hash sorting

sort{$tallies{my $a} <=> $tallies{my $b}}

This code flat out doesnt work. To see why lets take a look at this snippet:

#!perl -l my %tallies=(h=>30,a=>10,j=>1,p=>20); print "Keys:",keys %tallies; print "Bad :",sort{$tallies{my $a} <=> $tallies{my $b}} keys %tallies; print "Good:",sort{$tallies{$a} <=> $tallies{$b}} keys %tallies; __END__ Keys:phaj Bad :phaj Good:japh

So we see that in fact the code as written can be simplified down to

keys %tallies;

which obviously isnt what you want out of a sort as keys returns the keys in an arbitrary order that has to do with the values of the keys, the size of the hash and the insertion order, and later versions of perl throw in some initialization randomization for good measure.

Why is this so?

Because as stated the in-order function used resolves to undef <=> undef (Which you would have noticed if only warnings were enabled.) Why is that? Its because inside of the lexical scope of the sort you created two brand new variables named $a and $b which werent initialized at all. Its the equivelent of

sort {my ($a,$b); $a <=> $b } keys %tallies;

Which is much more obviously wrong. First off we use undef to access the value of the hash, this raises a warning and as it is string context is treated as the empty string. Since its unlikely you have that as a key the hash returns undef (although the end result would be the same whatever it returned) which is then in numeric context and thus coerced to a 0 while also raising warnings. So the end result is that every time sort asks if two keys are inorder it always gets 0 back from the comparison (indicating equality between the keys), and so it assumes its already inorder, and thus probably does not alter order of the list at all. (Im not sure about the stability of the sort in this case, given some tests it looks stable to me, but I wouldnt swear by it.)

Now to fix it you remove those my's from the picture. Now you are playing with something totally different. The variables $a and $b (along with a bunch more) are special cased global variables. They are special cased not to throw warnings when used without declaration under strict. And this is because the internal sort routine uses them to pass out the values of the two keys it is comparing. I think the others have covered satisfactorily the rest of whats going on, but I didnt notice anyone outright noting the error in the code so I thought I should point it out.

HTH


---
demerphq

<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...