Re: scope all wrong? in Mathematica 4.1
- To: mathgroup at smc.vnet.net
- Subject: [mg31861] Re: scope all wrong? in Mathematica 4.1
- From: "Alan Mason" <swt at austin.rr.com>
- Date: Fri, 7 Dec 2001 05:57:00 -0500 (EST)
- References: <9ul2ft$6m3$1@smc.vnet.net>
- Sender: owner-wri-mathgroup at wolfram.com
In general, Mathematica has complicated rules for when and how its functions hold their arguments, which can lead to semantic surprises. Users can change these attributes at their own risk. In particular, the right-hand side of a SetDelayed such as uu[...] := x is normally not evaluated, and the left-hand side is normally wrapped in HoldPattern. Just how these rules work in conjunction with the pattern matcher is a mystery, but they definitely are not working correctly in Fateman's first example --- rr[x_] := Module[{x}, x = 5; Print["x is ", x]]. The system needs to unwrap the various Holds in the right order and process first the first argument {...}of Module giving the locals and preempt the pattern matcher if there is a clash. Presumably this should be done before Mathematica's uniqueifying rules (appending $n to local variable names to make them unique) are performed. Could be a timing problem. The handling of Hold and ReleaseHold is tricky and this may explain some other bugs, e.g. why in version 4.1 Collect[e_, patt_, func] incorrectly releases any Holds present in e. In view of the above, I think the Fateman's second example, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x, actually shows Mathematica doing something correctly :=). The x_ should correspond to the x on the right-hand side, whereas the x in the PatternTest, being on the LHS, should define and/or update a new variable x separate from whatever x_ matches. Also, on a fresh startup of Mathematica v4.1 I get no extraneous printout. Fateman's third example, Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]], illustrates some interesting behavior when run repeatedly, as in the following notebook. I do not find that x is changed to 5. However, the printed statements become more numerous with each subsequent run. Examination shows that Mathematica is defining a new version of uu with each run, parameterized by the current local name x$9, x$10, etc. for the local x, and is running all the versions. This is as it should be. Surprisingly, however, these variables are not allocated on the stack but seem to be stored on the heap -- one has access to them and can change them. I have not been able to change the global x from 400 to 5, but x$9 is also in essence global (it didn't disappear from any stack) and if I reassign x$9 to 44, say, and run the Module[...] again, x$9 *is* changed back to 5. This is not happening to x, though -- x remains 400. In a way this is good, since one doesn't expect the global x to be changed, but it also seems inconsistent since x$9 is just as global as x . It would appear that local variables in Mathematica are not treated as such if they parameterize global objects defined inside a module; instead, the system keeps track of them even after their scope disappears. This enables Mathematica to distinguish dynamically between different instances of, e.g., programmatically generated rules parameterized by some argument(s), but seems to muddy the distinction between local and global variables. Why does Mathematica behave this way, rather than just plugging the value of x$n directly into the rule and then letting x$n go out of scope? Maybe because in principle it allows the user to change x$n and therefore also the rule (this is the essence of RuleDelayed, I suppose); but users will typically not know what alias to use for the local variable x in order to change it (the only way to find this alias is to do a ?uu). So I wonder if this hypothetical advantage warrants the apparent inconsistency that I noted above. In[1]:= x = 400 Out[1]= 400 In[2]:= Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]] in Module, x is \[InvisibleSpace]x$9 In[3]:=Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]] x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 in Module, x is \[InvisibleSpace]5 In[4]:= Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]] x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 in Module, x is \[InvisibleSpace]5 In[5]:= Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]] x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 x is \[InvisibleSpace]5 in Module, x is \[InvisibleSpace]5 In[6]:= ?uu Global`uu \!\(\* InterpretationBox[GridBox[{ {GridBox[{ {\(uu[x_?\((\((x$9 = 5; Print["x is ", x$9]; True)\) &)\)] := x\)}, {" "}, {\(uu[x_?\((\((x$10 = 5; Print["x is ", x$10]; True)\) &)\)] := x\)}, {" "}, {\(uu[x_?\((\((x$11 = 5; Print["x is ", x$11]; True)\) &)\)] := x\)}, {" "}, {\(uu[x_?\((\((x$12 = 5; Print["x is ", x$12]; True)\) &)\)] := x\)} }, GridBaseline->{Baseline, {1, 1}}, ColumnWidths->0.999, ColumnAlignments->{Left}]} }, GridBaseline->{Baseline, {1, 1}}, ColumnAlignments->{Left}], Definition[ "uu"], Editable->False]\) In[7]:= x$9 = 44 Out[7]= 44 In[8]:= Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; Print["in Module, x is " , x]] (snip--AGM) In[9]:= {x, x$9} Out[9]= {400,5} Alan "Richard Fateman" <fateman at cs.berkeley.edu> wrote in message news:9ul2ft$6m3$1 at smc.vnet.net... > Consider the mathematica definition > > rr[x_] := Block[{x}, x = 5; Print["x is ", x]] > > what do you expect here? > > rr[z] --> x is 5 is printed. > but you might not expect > > rr[4] --> "Block::"lvsym": "Local variable specification{4} contains 4 > which is not a symbol or an assignment to a symbol." > > If you use Module instead of Block, you get > the same. > > However, > Block[{x = 4}, Block[{x}, x = 5; Print["x is ", x]]] > > prints x is 5 > > Using pattern matching for > substituting 4 for x in rr[4] even when x is bound seems > to be counter to what most programming language designers > would expect. > > > > Now look at > > uu[x_?((x = 5; Print["x is ", x]; True) &)] := x > > Usually when one defines a program, nothing is printed. > Here, we get > x is 5 > 5 > x is 5 > > If we do this: > x =400 > uu[70] > x is 5 printed > the value returned is 70 > and the global x is 5. > > Try this: > Module[{x}, uu[x_?((x = 5; Print["x is ", x]; True) &)] := x; > Print["in Module, x is " , x]] > > The expectation in a system supporting lexical scope > with Module > is that no use of x inside the module would escape. > But it does. The global x is set to 5. > > > The reason this all came up is in correspondence suggesting > that programs in one computer algebra system could be > translated into another. If systems are semantically > "surprising", it is more difficult. I wonder how much > of mathematica internally depends on wrong scope, or how > much of the code is susceptible to bugs because of unexpected > capture of names. (I suspect that this has caused a proliferation > of package names e.g. MySecretNameSpace`x in Mathematica > routines). > > RJF > >