Today I was working on something and needed to print out a value, and the value times four, while incrementing the value by four every time. It was during dev/test so I was tweaking and running and extending and tweaking so the code evolved in strange ways. (Er the strangeness may also have to do with that perl programmers (bad)habit of trying to do a million things in one statement.) In the end it resulted in code like the printf line below
print "order1.pl\n"; print 'printf "%4d : %3d\n",$ofs,(($ofs+=4)-4)*4',$/; for ($ofs=0;$ofs<10;) { printf "%4d : %3d\n",$ofs,(($ofs+=4)-4)*4 }
Now, before you get all hot to trot and point out there are a zillion ways to write this more intelligently please understand that this is a reduction of the situation to its minimal case. It wasnt within a for loop, and in the end it all got complete refactored into something much more reasonable than what I am discussing here.
So whats the issue you say? Well the code doesnt work as I expected it to. It prints out the following:
order1.pl printf "%4d : %3d\n",$ofs,(($ofs+=4)-4)*4 4 : 0 8 : 16 12 : 32
Which is not what I expected. But the following code with only a tiny and apparently meaningless change makes it work as expected
print "order2.pl\n"; print 'printf "%4d : %3d\n",$ofs-0,(($ofs+=4)-4)*4',$/; for ($ofs=0;$ofs<10;) { printf "%4d : %3d\n",$ofs-0,(($ofs+=4)-4)*4 }
Which outputs
order2.pl printf "%4d : %3d\n",$ofs-0,(($ofs+=4)-4)*4 0 : 0 4 : 16 8 : 32
Which is exactly as expected. The change of the first parameter from $ofs to $ofs-0 causes it work "correctly".
Now this behaviour confused me. Why should the extra meaningless subtraction affect the order of operations? Well I had a poke around, and from what I could tell the order of operations doesnt change. So what gives?
Well, after a while I remembered that vars are aliased in perl. printf gets whichever variable it was passed by alias, not by copy. So with the first variant the _variable_ $ofs gets put on the stack, then its incremented when evaluating the second expression to go onto the stack. Whereas the second case the expression $ofs-0 is evaluated and then the result is placed on the stack.
Now as a last point, im not real sure that there is any guaranty that the parameters will be evaluated in any given order. I assume its left to right only because of DWIM.
All told this was a case of outsmarting myself, and a good reason to avoid overly complicated constructs in a misplaced attempt at brevity. I spent way longer figuring out what was going on by pulling out B::Terse and friends (although admittedly without much success) than I ever would have if i had rewritten the statement as several. (Er, I did learn one or two things so it wasnt all wasted :-)
Anyway, hope you find this interesting, and hope it saves somebody the time I wasted figuring it out writing it up. :-)
---
demerphq
<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
|
---|