10
$\begingroup$

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

$\endgroup$
4
  • $\begingroup$ 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 $\endgroup$
    – Szabolcs
    Feb 25, 2012 at 0:03
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Feb 25, 2012 at 0:09
  • $\begingroup$ That's all consistent with my understanding. I wrote a short answer. $\endgroup$
    – Szabolcs
    Feb 25, 2012 at 0:22
  • 2
    $\begingroup$ 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? $\endgroup$
    – Szabolcs
    Feb 25, 2012 at 10:02

3 Answers 3

14
$\begingroup$

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

$\endgroup$
1
  • $\begingroup$ Alright, I yield. $\endgroup$
    – Mr.Wizard
    Feb 25, 2012 at 0:28
3
$\begingroup$

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.

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

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.