Re: Is this a bug?

*To*: mathgroup at smc.vnet.net*Subject*: [mg32066] Re: Is this a bug?*From*: "Alan Mason" <swt at austin.rr.com>*Date*: Fri, 21 Dec 2001 03:57:47 -0500 (EST)*References*: <9vs8ph$g1d$1@smc.vnet.net>*Sender*: owner-wri-mathgroup at wolfram.com

"Paul van Wamelen" <wamelen at math.lsu.edu> wrote in message news:9vs8ph$g1d$1 at smc.vnet.net... > Is the following a bug? > > Mathematica 4.1 for Sun Solaris > Copyright 1988-2000 Wolfram Research, Inc. > -- Motif graphics initialized -- > > In[1]:= k[x_] := Module[{},Print["hallo world"];x]; > > In[2]:= a[5] = 0; > > In[3]:= a[k[5]]++ > hallo world > hallo world > > Out[3]= 0 > > > I would have expected only one "hallo world" and it would seem to be > more efficient to only evaluate the k[5] once... > > The above example is not important but in the form below it had me > baffled for a while: > > In[4]:= tst[n_] := Module[{a}, > a[0] = a[1] = 0; > Do[a[Random[Integer,{0,1}]]++,{n}]; > {a[0],a[1]}] > > In[5]:= tst[50] > > Out[5]= {24, 24} > > (Does not add up to 50!) > > Thanks! Hello Paul, I think you've hit the jackpot with this example! Part The First: No, it's not a bug; you're seeing the standard Mathematica evaluation mechanism at work. It is not special to ++. On encountering a[k[5]]++, Mathematica first looks at a[k[5]] and evaluates it, then adds 1 to the result and looks at that, triggering another evaluation . Note that if a[k[5]]++ is replaced by k[5]++, there is only one evaluation and only one print statement results. Basically, Mathematica is proceeding very simple-mindedly, as can be seen by doing a Trace, see following notebook. It first evaluates k[5], then plugs it into a; but then it increments a[k[5]] (not a[5] directly!), causing a second bout of evaluation and hence a second print statement (a side effect). Thus Mathematica treats a[k[5]]++ and a[5]++ differently, even though k[5] is currently 5. Why might this be desirable? Because k is SetDelayed. If I change it later k[5] will no longer be 5 in general, but the statement a[k[5]]++ (e.g., on the right-hand side of a delayed rule or assignment) will be correctly updated and a[?] will be incremented, where ? is the new (current) value of k[5]. You could say that Mathematica is hyperdynamic, always allowing for possible future changes to rules and their side effects, at the cost of some extra evaluations. If Mathematica were to compute a[k[5]]++ in the way you suggest, it would amount to assuming that ++ is an atomic operation, during which no rules (in particular, k) could change. But even if ++ were atomic, such a treatment would be inconsistent with Mathematica's general view of things. Part The Second: Yes, it is a bug. Your second example, with k replaced by Random, gives a striking illustration of when Mathematica's behavior is EXTREMELY UNDESIRABLE! Why? Because people don't expect it, to say the least. By its very nature, Random[] is going to defeat Mathematica's strategy because it differs at each call. Thus the double call of Random that Mathematica makes can give inconsistent results -- the value it returns the first time need not be the same the second time. Thus your example is special to Random and similar hypervolatile functions. For normal k, Mathematica's approach works fine. By the way, I think your example meets Withoff's criterion of a situation where Mathematica's handling of SetDelayed (with "extra" evaluations not done "in private") has bad practical consequences, although again, mercifully limited to Random (but extending also, I suppose, to any function k that calls Random). See David Withoff's post (second of four) "Re Re Scope all wrong...", Dec. 10, 2001 in MathGroup Archives. The following notebook has two parts. The second does a Trace of tst[5] and I've commented the "smoking gun". Alan In[1]:= k[x_] := Module[{},Print["hallo world"];x]; a[5] = 0; Out[1]= \!\(Null\^2\) In[2]:= a[k[5]] hallo world Out[2]= 0 In[3]:= Trace[a[k[5]]++] hallo world hallo world Out[3]= {a[k[5]]++,{{k[5], Module[{},Print[hallo world];5],{Print[hallo world]; 5,{Print[hallo world],{MakeBoxes[hallo world,StandardForm], "hallo world"},Null},5},5},a[5], 0},{a[k[5]]= 1,{{k[5],Module[{},Print[hallo world];5],{Print[hallo world]; 5,{Print[hallo world],{MakeBoxes[hallo world,StandardForm], "hallo world"},Null},5},5},a[5]},1},0} In[4]:= a[5] Out[4]= 1 (**************************************************************) In[123]:= tst[n_] := Module[{a}, a[0] = a[1] = 0; Do[a[Random[Integer,{0,1}]]++;Print[{a[0], a[1]}],{n}]; Return[ {a[0],a[1]}]] In[128]:= Trace[tst[5]] (*tst[5]*) {1,0} {2,0} {2,3} (* WHAT?! YOU'RE KIDDING! *) {4,3} {4,5} Out[128]= {tst[5],Module[{a$},a$[0]=a$[1]=0; Do[a$[Random[Integer,{0,1}]]++;Print[{a$[0],a$[1]}],{5}]; Return[{a$[0],a$[1]}]],{a$88[0]=a$88[1]=0; Do[a$88[Random[Integer,{0,1}]]++;Print[{a$88[0],a$88[1]}],{5}]; Return[{a$88[0],a$88[1]}],{{a$88[1]=0,0},a$88[0]=0, 0},{Do[a$88[Random[Integer,{0,1}]]++; Print[{a$88[0],a$88[1]}],{5}],{a$88[Random[Integer,{0,1}]]++; Print[{a$88[0], a$88[1]}],{a$88[Random[Integer,{0,1}]]++,{{Random[Integer,{0,1}], 0},a$88[0], 0},{a$88[Random[Integer,{0,1}]]=1,{{Random[Integer,{0,1}],0}, a$88[0]},1},0},{{{a$88[0],1},{a$88[1],0},{1,0}}, Print[{1,0}],{MakeBoxes[{1,0},StandardForm], RowBox[{{,RowBox[{1,,,0}],}}]},Null}, Null},{a$88[Random[Integer,{0,1}]]++; Print[{a$88[0], a$88[1]}],{a$88[Random[Integer,{0,1}]]++,{{Random[Integer,{0,1}], 0},a$88[0], 1},{a$88[Random[Integer,{0,1}]]=2,{{Random[Integer,{0,1}],0}, a$88[0]},2},1},{{{a$88[0],2},{a$88[1],0},{2,0}}, Print[{2,0}],{MakeBoxes[{2,0},StandardForm], RowBox[{{,RowBox[{2,,,0}],}}]},Null}, Null},{a$88[Random[Integer,{0,1}]]++; Print[{a$88[0], a$88[1]}],{a$88[Random[Integer,{0,1}]]++,{{Random[Integer,{0,1}], (* SMOKING GUN HERE *) 0},a$88[0], 2},{a$88[Random[Integer,{0,1}]]=3,{{Random[Integer,{0,1}],1}, a$88[1]},3},2},{{{a$88[0],2},{a$88[1],3},{2,3}}, (* OH REALLY? *) Print[{2,3}],{MakeBoxes[{2,3},StandardForm], RowBox[{{,RowBox[{2,,,3}],}}]},Null}, Null},{a$88[Random[Integer,{0,1}]]++; Print[{a$88[0], a$88[1]}],{a$88[Random[Integer,{0,1}]]++,{{Random[Integer,{0,1}], 1},a$88[1], 3},{a$88[Random[Integer,{0,1}]]=4,{{Random[Integer,{0,1}],0}, a$88[0]},4},3},{{{a$88[0],4},{a$88[1],3},{4,3}}, Print[{4,3}],{MakeBoxes[{4,3},StandardForm], RowBox[{{,RowBox[{4,,,3}],}}]},Null}, Null},{a$88[Random[Integer,{0,1}]]++; Print[{a$88[0], a$88[1]}],{a$88[Random[Integer,{0,1}]]++,{{Random[Integer,{0,1}], 0},a$88[0], 4},{a$88[Random[Integer,{0,1}]]=5,{{Random[Integer,{0,1}],1}, a$88[1]},5},4},{{{a$88[0],4},{a$88[1],5},{4,5}}, Print[{4,5}],{MakeBoxes[{4,5},StandardForm], RowBox[{{,RowBox[{4,,,5}],}}]},Null},Null}, Null},{{{a$88[0],4},{a$88[1],5},{4,5}},Return[{4,5}]},Return[{4,5}]}, Return[{4,5}],{4,5}}