CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Fun With Perl: Perl Quizzes - Learn Perl the Fun Way:
Counting again!

 



Paul
Enthusiast

Feb 12, 2002, 5:21 AM

Post #1 of 7 (35110 views)
Counting again! Can't Post

This is sort of related to the other thread but can anyone tell me what the following 2 examples print and why Wink

my $num = 0;

print ++$num - --$num + --$num;
print ++$num - $num-- + $num--;


unknownSym
stranger

Feb 12, 2002, 8:28 AM

Post #2 of 7 (35097 views)
Re: [RedRum] Counting again! [In reply to] Can't Post

I'm sorry I cheated. I executed the code, but I won't show the answers.

Before I executed the code I thought the first print statement would print 0, and the second print statement would print -1, but I was wrong.

I have no idea why. It's completely boggling. I would like to say that it has something to do with the order of operations, but I'm not sure.


fashimpaur
User

Feb 12, 2002, 8:49 AM

Post #3 of 7 (35095 views)
Re: [RedRum] Counting again! [In reply to] Can't Post

RedRum,

Here we meet again. Let's look at what is being asked....

my $num = 0;

print ++$num - --$num + --$num;
print ++$num - $num-- + $num--;

Since no parenthesis exist, then order of precedence is in effect.

Line 3 states:

print ++$num - --$num + --$num; # this causes a race condition between
# precedences.


What actually occurs is this:

The compiler tries to increment $num from 0 to 1 and assign 1 to $num. At
the same time, it tries to decrement $num from 1 to 0. The result of which
appears in the incremented $num. Because the decremented $num then finishes,
it's value is 0. The first part of the equation then becomes 0 - 0. At this point,
the compiler tries to decrement the value of num (0) and add it to the result of
the first part of the equation. 0 + -1 = -1. Thus, -1 is printed to the output.


REMEMBER: $num is now -1 at this point!

Line 4 states:

print ++$num - $num-- + $num--; # precedence race occurs again.

The compiler now increments $num from -1 to 0 and assigns 0 to the value of $num.
The next step says to post decrement the value of $num (0) to -1. The pre-increment
value of $num is also set to -1 because it is not finished yet. Thus, the first part of
the equation is -1 - -1 == -1 + 1. Finally the third part of the equation can be processed.
The value of $num is post decremented from -1 to -2. The final equation
is -1 + 1 - 2. Therefore, -2 is printed to the output.

Okay. Now lets test the theory:

try:


$num = 0;
print ++$num + ++$num;

According to the theory, the output should be 4.

The compiler increments $num to 1, the second part of the equation increments 1 to 2.
2 is put in the first part of the equation making the final equation 2 + 2 == 4. TRUE!

In summary, we need to be careful to explicitly tell the compiler what we really want by
using parenthesis to indicate which action should be done and in what order.

How'd I do?


Dennis

$a="c323745335d3221214b364d545".
"a362532582521254c3640504c3729".
"2f493759214b3635554c3040606a0",
print unpack"u*",pack "h*",$a,"\n\n";


Paul
Enthusiast

Feb 12, 2002, 8:55 AM

Post #4 of 7 (35092 views)
Re: [fashimpaur] Counting again! [In reply to] Can't Post

Not a bad analysis :)

...although I'm just starting you off with easy questions Sly


mhx
Enthusiast

Feb 12, 2002, 9:39 AM

Post #5 of 7 (35085 views)
Re: [RedRum] Counting again! [In reply to] Can't Post

Now, that's a tough one ;-)

Let's have a look at (what I think is) Perl's parse tree of the expression in the first print statement:


Code
       ++$num    --$num 
\ /
\ /
( - ) --$num
\ /
\ /
( + )


That tree is evaluated top-down, from left to right. Which means, the nodes are evaluated in the following order:


Code
     1 ++$num  2 --$num  
\ /
\ /
3 ( - ) 4 --$num
\ /
\ /
5 ( + )


So, first of all $num is being incremented. The interesting part (and the one that I'm not sure about) is: Does Perl keep a copy of the incremented value in the node for further evaluation or does it only keep a reference to $num (which it already has)? Now, this is pure speculation, but in the favour of speed I would only keep a reference instead of creating a copy. Let's assume it is that way.

Next, $num is being decremented. So it is back at zero now. The next node subtracts the values of its children, which are both zero (as we assume Perl keeps only references). And zero minus zero is obviously zero. If Perl would keep copies of pre(in|de)cremented values, the result would have been 1 instead. However, Perl has to create a new scalar value to hold the result.

What happens next is that $num is autodecremented again and now holds a -1. The final node adds the zero and the -1, which results in -1. (In case Perl would make copies, the result would be 1 + (-1) = 0.)

So the result should be either -1 or zero. My guess would be -1, because of the performance issue noted above.

Now, let's move on to the second print statement. The parse tree is exactly the same, just that there are two postdecrements instead of the predecrements in the first expression:


Code
     1 ++$num  2 $num--  
\ /
\ /
3 ( - ) 4 $num--
\ /
\ /
5 ( + )


The difference between a predecrement and a postdecrement is that Perl has to create a copy of the decremented value. (There's no option as for the predecrement.) Perl creates a copy, and the decrements the value. The following quote from the Camel Book, which I had a look into to see if there's a defined behaviour for expressions with multiple auto(in|de)crement operators, makes me believe that I'm right in my opinion that the pre(in|de)crement operators do not make copies:


Quote
The optimizer will notice this and optimize the post-increment into a pre-increment, because that's a bit faster to execute.


What happens in the second expression is that $num (now with a value of -1) is being incremented. So it's zero now. Next, a copy of $num is created in the second node, and $num is decremented. That means $num is now -1, and when the third node is evaluated, the result is -1, since the first node still holds a reference to the recently decremented $num.

Node 4 again created a copy of $num (-1) that is added in node 5 to the result of node 3 (also -1). So the result of the expression in the second print statement should be -2.

As a conclusion, I'm pretty sure the results are -1 and -2, although I could also think of 0 and -1, if Perl would create copies for the pre(in|de)crement operations.

-- mhx

P.S.: I've run the code through perl right before I posted this and I was happy to see that I can't be very far from the truth. I'm going to investigate this a little further...

At last with an effort he spoke, and wondered to hear his own words, as if some other will was using his small voice. "I will take the Ring," he said, "though I do not know the way."

-- Frodo



fashimpaur
User

Feb 12, 2002, 10:21 AM

Post #6 of 7 (35080 views)
Re: [mhx] Counting again! [In reply to] Can't Post

Okay. A fancy way of saying what I did. Tongue
Dennis

$a="c323745335d3221214b364d545".
"a362532582521254c3640504c3729".
"2f493759214b3635554c3040606a0",
print unpack"u*",pack "h*",$a,"\n\n";


mhx
Enthusiast

Feb 12, 2002, 10:51 AM

Post #7 of 7 (35077 views)
Re: [fashimpaur] Counting again! [In reply to] Can't Post

Dennis,

While I agree with you on the first part, I have my problems with your explanation of what's happening in the second print statement.


Quote
Line 4 states:

print ++$num - $num-- + $num--; # precedence race occurs again.

The compiler now increments $num from -1 to 0 and assigns 0 to the value of $num.


Agreed. Cool


Quote
The next step says to post decrement the value of $num (0) to -1. The pre-increment
value of $num is also set to -1 because it is not finished yet.


You are right in that $num is set to -1 by the post-decrement, but the second operand of the subtraction cannot be -1, because it's a post-decrement. So while the first operand is more or less undefined (but we assume it's -1, because $num has already been decremented), the second operand must be 0.


Quote
Thus, the first part of the equation is -1 - -1 == -1 + 1.


Thus, I'd say the result of the first operation is (-1 - 0 = -1).


Quote
Finally the third part of the equation can be processed. The value of $num is post decremented from -1 to -2.


Although $num is decremented, -1 is still being used to evaluate the expression.


Quote
The final equation is -1 + 1 - 2. Therefore, -2 is printed to the output.


The final equation is -1 + (-1) = -2. Same result, different way of explaining it. The problem with your explanation is that there's no real difference between the behaviour of pre- and post-..crement operators. Both perform the same task (increment or decrement a value), but the value they evaluate to is different. In your final equation, you assume that all post-..crementing steps are already done when the expression is evaluated. If that was true,


Code
$num = 0; 
print $num++;
print $num;


would print 1 and 1. And how would you explain


Code
$num = 0; 
print $num++ + $num++;
print $num;


printing 1 and 2? Wink

Cheers,
-- mhx

At last with an effort he spoke, and wondered to hear his own words, as if some other will was using his small voice. "I will take the Ring," he said, "though I do not know the way."

-- Frodo


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives