Why does ++++x return an increment of 2 when the value of x is only incremented by 1?

This line returns 3:

x = 1; ++++x


However, the value of x after the increment is only 2. Similarly, this line returns 5, while the value of x is again only 2.

x = 1; ++++++++x


Why does it return 3 and 5 respectively in the above examples?

(This question is intended as a puzzle, and to encourage people to think through an opaque evaluation chain.)

-
I'm too sleepy to write an answer but the explanation is clear if you TracePrint, and consider the HoldAll causes evaluating to from outside to inside as we disussed in chat the other day –  Szabolcs Feb 25 '12 at 0:03
@Szabolcs this might be more involved than you think, but of course I don't know what you think. I added an example you should also consider. –  Mr.Wizard Feb 25 '12 at 0:09
That's all consistent with my understanding. I wrote a short answer. –  Szabolcs Feb 25 '12 at 0:22
Doesn't it happen on all releases of 8? I get exactly the same what you get in 7. Is it possible that those who got a different result simply forgot to set a value to x? –  Szabolcs Feb 25 '12 at 10:02

TracePrint will show you what happens:

PreIncrement takes it's argument x, evaluates it (let's call the result result), then evaluates x = result+1. Note that PreIncrement has HoldFirst.

Now ++(++x) evaluates ++x first yielding 2, then evaluates (++x) = 2+1 resulting in an error (trying to assign to PreIncrement) and returning 3.

This also explains why adding yet another layer of PreIncrement will increment the result again.

Here's a self-implemented ++ to make the above more clear. The behaviour is exactly the same:

-
Alright, I yield. –  Mr.Wizard Feb 25 '12 at 0:28

A quick test shows that assignment returns the right hand side even if the left hand side is protected:

Protect[a]; a=b
(*
==> b
*)


Now ++x (i.e. Preincrement[x]) is equivalent to x=x+1. Indeed, this is true even for the argument evaluation:

++foo[Print["x"]];


outputs "x" twice (and gives a "recursion limit exceeded"), just like

foo[Print["x"]]=foo[Print["x"]]+1;


Therefore

++++x


is equivalent to

++x = ++x +1


where the left side is unevaluated (due to HoldFirst) but cannot be set (due to Protected), but the expression nevertheless evaluates and returns the result of ++x + 1, which of course increments x once, but gives 2 more than the old value of x.

-

Using FullForm on the expression yields

++++x // FullForm

PreIncrement[PreIncrement[x]]


PreIncrement increments the value of its argument by one, and returns the new value; notice that it has the attribute HoldFirst. Mathematica 8 issues a warning here that PreIncrement is protected and cannot be incremented, while strangely enough printing 3 nevertheless. In any case, x is incremented only once (by the inner PreIncrement), giving it a value of 2.

-
"while curiously enough printing 3 nevertheless" -- that's rather the point of the question, isn't it? –  Mr.Wizard Feb 25 '12 at 0:01
I'm running 8.0.4 and I get ++++x returned unevaluated, alongside with the messages, of course. –  rcollyer Feb 25 '12 at 0:04
@rcollyer oh nuts, they fixed it. –  Mr.Wizard Feb 25 '12 at 0:05
@rcollyer I'm running 8.0.4 and it evaluates (plus the mentioned warning). Odd –  David Feb 25 '12 at 0:08
I get PreIncrement[PreIncrement[x]] when using FullForm, but ++++x when not. –  rcollyer Feb 25 '12 at 1:11