# Problem with function inside brackets. Bug? [duplicate]

This code adds random digits to lists, and it works fine:

a = {{1}, {2}, {3}};
Do[
j = RandomInteger[{1, Length[a]}];
AppendTo[a[[j]], RandomInteger[9]];
Print[a], {i, 5}];

(* {{1,7},{2},{3}}
{{1,7},{2,2},{3}}
{{1,7},{2,2},{3,9}}
{{1,7},{2,2},{3,9,1}}
{{1,7,2},{2,2},{3,9,1}}  *)


But if I replace the 'j' inside the [[]] with the definition j in the previous line, everything goes haywire:

a = {{1}, {2}, {3}};
Do[
AppendTo[a[[RandomInteger[{1, Length[a]}]]], RandomInteger[9]];
Print[a], {i, 5}];

(* {{1},{1,7},{3}}
{{1},{1,7},{1,4}}
{{1,7},{1,7},{1,4}}
{{1,7},{1,7},{1,7,9}}
{{1,7,9},{1,7},{1,7,9}} *)


Is this a bug or something I'm doing wrong?

• What exactly do you mean by "everything goes haywire"? It's hard to tell what's wrong, given the random numbers in the code (and therefore the outputs that are never the same). Can you elaborate? Nov 10 '16 at 21:09
• @march Initially a = {{1}, {2}, {3}}; after the first step of appending it's {{1},{1,7},{3}} - you append 7 to {2} and get {1,7}. Nov 10 '16 at 21:13
• I believe I see the problem. RandomInteger[{1, Length[a]}] is evaluated twice in the second case. I will write a quick answer. Nov 10 '16 at 21:21
• Answers by @Szabolcs and @march dispel the mystery. Note also that this case is a good use case for BlockRandom; that is, as an alternative to your first approach you could also use Do[AppendTo[a[[BlockRandom[RandomInteger[{1, Length[a]}]]]], RandomInteger[9]]; Print[a], {i, 5}];
– kglr
Nov 10 '16 at 22:11
• Related, possible duplicate: (107619) Nov 12 '16 at 8:42

Here's the issue. In the second (non-working) code,

RandomInteger[{1, Length[a]}]


is evaluated twice, as we can see by Traceing the evaluation:

SeedRandom[2]
a = {{1}, {2}, {3}};
Trace[AppendTo[a[[RandomInteger[{1, Length[a]}]]], RandomInteger[9]], TraceInternal -> True]

1. {RandomInteger[9], 8}
2. AppendTo[a[[RandomInteger[{1, Length[a]}]]], 8]
3. {{a, {{1}, {2}, {3}}}, {{{{a, {{1}, {2}, {3}}}, Length[{{1}, {2}, {3}}], 3}, {1, 3}}, RandomInteger[{1, 3}], 3}, {{1}, {2}, {3}}[[3]], {3}}
4. a[[RandomInteger[{1, Length[a]}]]] = Append[{3}, 8]
5. {Append[{3}, 8], {3, 8}}
6. a[[RandomInteger[{1, Length[a]}]]] = {3, 8}
7. {{{{a, {{1}, {2}, {3}}}, Length[{{1}, {2}, {3}}], 3}, {1, 3}}, RandomInteger[{1, 3}], 2}

We can see in Line 1 that RandomInteger[9] evaluates to 8, so we will be appending 8 to one of the lists. In Line 3, RandomInteger[{1, 3}] evaluates to 3, so we're going to append to a[[3]]. This happens on Line 5, where 8 is appended to {3} to make {3, 8}.

Now, the kicker: In Line 7, RandomInteger[{1, Length[a]}] is evaluated again, so it evaluates to a different number. In this case, it evaluates to 2, so instead of replacing a[[3]], we are replacing a[[2]] with {3, 8}. Hence the output after this evaluation is

a
(* {{1}, {3, 8}, {3}} *)


Now, the fix here is to do things the way you're doing it in the first code. I would probably wrap the entire thing in a Module with j as a local variable, but it's the same process.

• Ooooooh... Interesting. So not a bug, but that second evaluation sure seems like an iffy design feature. Thank you for your insight and the time you put into writing this up. This was instructive and helpful. Nov 10 '16 at 22:06
• @JerryGuern. Well, I think Szabolcs has a pretty good explanation of why the double evaluation occurs, in terms of what AppendTo is likely literally doing behind the scenes. I think that that particular "design choice" for AppendTo makes some amount of sense. Nov 10 '16 at 22:13

No, not a bug.

Let's think about how AppendTo may be implemented (even though the actual implementation isn't inspectable).

SetAttributes[appendTo, HoldFirst]
appendTo[a_, val_] := (a = Append[a, val])


What happens if we evaluate the following?

appendTo[ a[[ RandomInteger[{1,3}] ]],  x ]


It simply does this:

a[[ RandomInteger[{1,3}] ]] = Append[a[[ RandomInteger[{1,3}] ]], x]


That's because RandomInteger[...] didn't get evaluated before substitution due to the HoldFirst. Now we have two of them. And they may evaluate to different values. So we may get things like

a[[1]] = Append[ a[[3]], x ]


if the first random number we get is 1 and the second is 3.

I hope this makes it clear. I have a vague feeling that the same has been asked before in a different form.

• Would you kindly review the link I just added in the comments below the question, and vote to close this question as a duplicate if you feel that is appropriate? Nov 12 '16 at 8:43
• @Mr.Wizard I knew there had to be a duplicate! Nov 12 '16 at 8:54