Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
|
|---|
| Replies are listed 'Best First'. | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Re: print behavior
by ikegami (Patriarch) on Jul 09, 2007 at 18:47 UTC | |||||||||||||||||||||||||
Remember that arguments are passed by reference*, so print will see the change in $x caused by ++ (which must be evaluated before print is called). In detail,
is roughly equivalent to
except the order of the alias statements isn't defined. Given $x=0, @_ is ($x, $anon) which evaluates to (1, 0). In short, avoid modifying a variable in a parameter list expression when the variable appears elsewhere in that parameter list. * — "by reference" is different than "as a reference". | [reply] [d/l] [select] | ||||||||||||||||||||||||
by atemon (Chaplain) on Jul 10, 2007 at 09:24 UTC | |||||||||||||||||||||||||
With due respect to ikegami and all other monks, I strongly disagree with ikegami for the following reasons. If you keep the explanation I posted at Re: print behavior in mind, there is NO harm in modifying a variable in a parameter list expression when the variable appears elsewhere in that parameter list. Isn't it a nice obfuscation. | [reply] [d/l] [select] | ||||||||||||||||||||||||
by ikegami (Patriarch) on Jul 10, 2007 at 16:42 UTC | |||||||||||||||||||||||||
That's a lot of questions! Here goes... Answer to Question 1I'll do two examples, $x,$x,$x++:
$x,$x++,$x++:
$x,$x++,$x++, on a system that does the alias statments in a different order:
Answer to Question 2Your compiler probably does something like:
C doesn't guarantee the order either. Answer to Question 3The return value of $x++ is not $x. It's a new variable that contains the old value of $x. $x is incremented before the print call, but you are aren't printing $x. Check perlop. Answer to Question 4
or in even more detail
Answer to Question 5Guess what the following prints:
On my system, it prints 36556.
Notice how $x and $x+0 are different.
| [reply] [d/l] [select] | ||||||||||||||||||||||||
|
Re: print behavior
by FunkyMonk (Bishop) on Jul 09, 2007 at 17:50 UTC | |||||||||||||||||||||||||
| [reply] | ||||||||||||||||||||||||
|
Re: print behavior
by toolic (Bishop) on Jul 09, 2007 at 17:54 UTC | |||||||||||||||||||||||||
Try this: You should get this output, which is more like what you expect.
| [reply] [d/l] [select] | ||||||||||||||||||||||||
|
Re: print behavior
by atemon (Chaplain) on Jul 10, 2007 at 07:32 UTC | |||||||||||||||||||||||||
Hi Monks This behaviour is there with C/C++ "printf" also. We need to know how the "print" statement (see coments below ) is handling variables & its data. Our code in question is
All the arguments passed to the "print" is kept in a stack! print will push arguments from right-to-left into the stack. Inthe above case value of $x goes into stack (corresponding to $x++). After the first "push", $x is incremented and on second "push" new value of $x is pushed. Then it start poping to print. For sure it will pop 1 first and then 0. So it will print 10. A program to demo this can be
Again funny facts :)
This will print 110 for sure, because the value of $x is NOT changed after first push. Then what would be
In case of "C" it will print 210 as expected. but the output you will get in perl is 201. If I make a table with more $x++ in print, it will be as follows (assuming that initial value of $x is 0 ).
"C" is working as I explained above. Why Perl is behaving differently when we have "$x,$x++,$x++" ? Answer is again stacks. when there are more than one expressions in same statement, perl uses another stack for evaluating them. ie, it wll push 0 to stack first. Then increments $x to 1. Then again it pushes 1 to stack and increments it to 2. Now all operations are over. Now Perl with pop contents of the operation stack and push to print stack. Then push the last $x. So it will print "201" for print $x,$x++,$x++Following program will demonstrate the entire thing :)
Isn't this a nice hack for obfuscation ?
Comments
Cheers! --VC UPDATE : I am not sure about all C compilers. I got above behavior with "gcc on FC6 & Turbo C on Windows XP". Also for Perl I tested with "Active Perl On Windows XP & Perl on FC6". I was NOT trying to say Perl & C will behave alike, but I was trying to say that this IS there with most of the implementation of C (gcc on FC6 and turbo C on Windows XP) & Perl (Active Perl On Win XP and perl on FC6). SORRY if misleading. | [reply] [d/l] [select] | ||||||||||||||||||||||||
by ikegami (Patriarch) on Jul 10, 2007 at 16:57 UTC | |||||||||||||||||||||||||
You're making the mistake of assuming Perl and C will behave the same on all systems. Statements like "This will print 110 for sure" and "In case of 'C' it will print 210 as expected." are wrong. The order in which the args are evaluated is not defined in either language. That's why it's harmful to modify a variable in a parameter list expression when the variable appears elsewhere in that parameter list. | [reply] | ||||||||||||||||||||||||
by atemon (Chaplain) on Jul 12, 2007 at 03:17 UTC | |||||||||||||||||||||||||
I am not sure about all C compilers. I got above behavior with "gcc on FC6 & Turbo C on Windows XP". Also for Perl I tested with "Active Perl On Windows XP & Perl on FC6". I was NOT trying to say Perl & C will behave alike, but I was trying to say that this IS there with most of the implementation of C (gcc on FC6 and turbo C on Windows XP) & Perl (Active Perl On Win XP and perl on FC6). SORRY if misleading. Obfuscation is NOT the only measure of expertise. | [reply] | ||||||||||||||||||||||||
by polettix (Vicar) on Jul 11, 2007 at 11:34 UTC | |||||||||||||||||||||||||
Also, a note about the undefined order of execution. The fact that some compilers seem to behave in a certain manner does not mean that you can rely on it. It means that they can change their mind whenever they want, without notice, and it's simply plain wrong to rely on it. This said, it can probably be useful only in some golfing competition, where you can be sure that a certain version of perl (with the lowercase "p") on a certain architecture will be used, and you can thus take advantage of any implementation decision, feature or bug this perl exhibits. Usage in obfuscation is weaker, IMHO, because it could behave differently across different versions or architectures. Flavio | [reply] | ||||||||||||||||||||||||
|
Re: print behavior
by polettix (Vicar) on Jul 10, 2007 at 13:33 UTC | |||||||||||||||||||||||||
Flavio | [reply] | ||||||||||||||||||||||||
|
Re: print behavior
by bart (Canon) on Jul 11, 2007 at 12:20 UTC | |||||||||||||||||||||||||
and figure out why this does print "00". The reason for the difference is that on your case the first parameter is an alias to the variable $x, while in my case it's an expression with a stringified copy of the value of $x at the time the parameter value was evaluated. An alias can still change its value later – when the value of $x changes. A copy can not. | [reply] [d/l] [select] | ||||||||||||||||||||||||
|
Re: print behavior
by Moron (Curate) on Jul 12, 2007 at 08:36 UTC | |||||||||||||||||||||||||
1) evaluate a list of two arguments 0) $x = 0 and 1) $x++ = 0. 2) increment $x so that the list of arguments is now 0: $x=1 and 1) $x++ = 0 (stays unchanged - that's what postincrement is for!) 3) Call the function with the two arguments whose values we just established should be 1 and 0 respectively. Then we see that the results are the only results we should expect to happen!
__________________________________________________________________________________
^M Free your mind!
| [reply] | ||||||||||||||||||||||||