Confusing behavior when passing a variable vs. inlining a function call

Mathematica is an expression rewriting language. When it evaluates:

q[[RandomInteger[{1, 2}]]] += 1

It first rewrites it as:

q[[RandomInteger[{1, 2}]]] = q[[RandomInteger[{1, 2}]]] + 1

The result is that RandomInteger[{1, 2}] gets rewritten twice, possibly as different random integers.


The main problem is that q[[k]] += 1 is equivalent to q[[k]] = q[[k]] + 1, and so RandomInteger gets called twice. When the random number is the same (which happens half the time), then the behavior is what you expect. When the random numbers are different, then the behavior is completely different. Here is a version of your code where I add some debugging (I also removed the completely superfluous Return statement):

f1[n_] := (
    q = {0,0};
    Do[q[[Echo@RandomInteger[{1,2}]]] += 1; Print[q], n];
    q
)

Here is a short example:

SeedRandom[3]
f1[3]

1

2

{0,1}

2

2

{0,2}

2

1

{3,2}

{3, 2}

Let's see what happens. In the first iteration, we have:

q[[2]] = q[[1]] + 1

and so the result is {0, 1}. The second iteration does:

q[[2]] = q[[2]] + 1

and so the result is {0, 2}. The final iteration does:

q[[1]] = q[[2]] + 1

and so we get {3, 2}.