10

This line returns 3:

x = 1; ++++x

enter image description here

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

enter image description here

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.)

Mechanical snail
  • 2,422
  • 1
  • 16
  • 35
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 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 00: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 00:09
  • That's all consistent with my understanding. I wrote a short answer. – Szabolcs Feb 25 '12 at 00:22
  • 2
    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

3 Answers3

14

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.


Mathematica graphics


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

Mathematica graphics

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
3

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.

David
  • 14,911
  • 6
  • 51
  • 81
2

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.

celtschk
  • 19,133
  • 1
  • 51
  • 106