MathGroup Archive 2001

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Re: Re: scope all wrong? in Mathematica 4.1

  • To: mathgroup at smc.vnet.net
  • Subject: [mg31947] Re: [mg31914] Re: Re: scope all wrong? in Mathematica 4.1
  • From: David Withoff <withoff at wolfram.com>
  • Date: Thu, 13 Dec 2001 01:08:56 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

> I think that ideal behavior would be to issue a warning "argument of
> function is shadowed by local variable, will have no effect"

I would go along with that.  Probably the only objection would be that
adding such a message may not be worth the effort, since essentially
no on ever makes this mistake anyway.

I found the next comment to be fairly interesting:

> To barge right in and replace x in the body of the Module when
> this x should refer to the local variable strikes me as too simplistic and
> is therefore a surprise.

Does this mean that the behavior was surprising because it wasn't
sufficiently complicated?  The only times that I have been confused
by Mathematica was when I expected it to be more complicated than
it really was.  Mathematica is actually a pretty simple system.

The two different ways of handling this situation can be
illustrated by comparing:

In[1]:= f[x_]:=Module[{x},x=5;Print["x is ", x]]

In[2]:= f[99]

Module::lvsym: Local variable specification {99} contains 99 which
   is not a  symbol or an assignment to a symbol.

Out[2]= Module[{99},99=5;Print[x is ,99]]

where, as you noted, the value associated with x in f[x_] just
goes barging right in to the right side of the rule, and

In[3]:= f = Function[{x},Module[{x},x=5;Print["x is ",x]]];

In[4]:= f[99]

x is 5

where the value associated with the x in Function[{x}, ...] respects
the local variable of same name in the Module.  So there really are
two qualitatively different ways of handling this situation.  The
decision on how to handle this in Mathematica was not made lightly.
Among the many considerations was the observation that most people
think of applying a rule as a qualitatively different operation
than evaluation of nested scoping constructs, and in particular
expect things like With[{x = 99}, Module[{x}, ...]] to be handled
differently than things like f[99] /. f[x_] :> Module[{x}, ...].

People who expect rule application to be handled like another
scoping construct may very well be disappointed by this design
choice.  I'm not sure it is possible to design a programming
language that matches everyone's expectations.  I would claim,
however, that there is ample precedent in other programming
languages for this aspect of the design of Mathematica, that
there is no absolute principle for choosing one design or the
other, and that in some sense it comes down to choosing what
will be most useful to most users most of the time.

>  I tried in my previous post to express what I think would have to be
> changed to accommodate "ideal" behavior.  In essence, some processing (and
> therefore unHolding) of the RHS of := -- to determine the locals and look
> for name clashes, and if neccessary preempt the pattern matcher -- would
> have to occur before the value that the system has determined for the
> pattern x_ on LHS is passed in to the RHS.  Currently, this passing is
> essentially instantaneous.

Yes, that is the other possibility (e.g. the behavior of the second
example above).  Things could certainly be done that.  It is obviously
debatable, of course, that this alternative is "ideal".

> 2) My comment about the local x$9 reemerging as a de facto global (growing
> wings as it were and flying the coop) does seem relevant to Fateman's
> concern about scope violation and "escaping" variables.  Variables like x$9
> are normally off-limits to programmers outside of the subroutine in which
> they are declared as local.  Does Mathematica rely on the uniqueness of x$n
> variable names to keep track internally of multiple versions of global rules
> generated programmatically inside a Module, by using them in effect as part
> of their "signature"? I know that I can change rules after the fact (i.e.,
> after the scope of x$n as originally declared in its subroutine has
> disappeared) by changing the x$n to which they have been "hard-wired".  Of
> course, no one who has used Mathematica entertains for a moment the
> possibility that local variables are escaping wholesale -- this would make
> Mathematica completely unusable, whereas in practice it's eminently usable
> (albeit with a steep learning curve).  But the observed phenomenon does seem
> to be a kind of "back door" and therefore not exactly kosher...

This is an observation about an implementational detail, rather than
anything fundamental about the language.  Values of local variables
are essentially always accessible in any programming system.  In typical
C or Fortran implementations, for example, you can inspect or modify
values of arbitrary local variables by using system-dependent commands
to determine the corresponding memory locations.  The only difference
is that, in Mathematica, those variables are more accessible.  In
Mathematica you can do it by finding the right sym$nnn variable
(analogous to finding the right memory location in other systems)
and then using ordinary evaluation or assignment (analogous to using 
memory "peek" and "poke" functions in other systems).  So that "back
door" exists in any system.

A lot of people rather like the accessibility of these private
variables, especially for debugging purposes.  It would be possible
to make them more well hidden in Mathematica by removing them from
the symbol table, but I hope that that doesn't happen.

There is a fairly clear statement in the documentation not to
mess with these variables unless you know what these variables
are doing and you have a good reason to mess with them.

> PS.  I think for clarity it would be best to include a code snippet showing
> exactly what I mean here.
> Here's a greatly abridged example from actual code:
> 
> \!\(\(\(setRules[sym_:  D, \ delayCircleDotEvaluation_:  0]\  := \
>       Module[{\ h, \ symL}, \[IndentingNewLine]If[Head[sym]\  =!= \ List, \
>           symL\  = \ {sym}, \
>           symL\  = \ sym]; \[IndentingNewLine]SetAttributes[
>           SmallCircle, {OneIdentity, \
>             Flat}]; \[IndentingNewLine]a_\ \[SmallCircle]\ b_\  /; \
>             Head[a] === Plus\  || \ Head[b] === Plus := \
>           Distribute[h[a, \ b]]\  /.
>             h -> SmallCircle\ ; \ \[IndentingNewLine]\((a_. \ S_\_u_)\)\ \
> \[SmallCircle]\ \((b_\ \ c_)\)\  := \
>           a\ b\ \ S\_u\ \[SmallCircle]\ c\  + \
>               a\ S\_u\ \[CircleDot]\ b\ c\  /; \
>             MemberQ[symL, \
>                 S]\ \  && \((FreeAllQ[b, symL]\  || \
>                   Head[b] ===
> 
> CircleDot)\);\[IndentingNewLine]];\)\(\[IndentingNewLine]\
> \)
>   \)\)
> 
> If you run  setRules and then do DownValues[\[SmallCircle], pick out the
> rule involving S, and do a FullForm, you will not find S but rather symL$n
> instead (its value is in fact that of S, but it is being held; Cases[rule,
> symL$n, {0, Infinity}] returns  {}).    If you change symL$n interactively,
> you will change rule accordingly. (But I thought symL$n was local!  So this
> really is a back door.)

Since I don't know what "run setRules" means (evaluate SetRules[] perhaps?)
or what "do DownValues[\[SmallCircle]" means (DownValues[\[SmallCircle]] is
a syntax error), and I don't know what this function is supposed to do, I
can't comment on this example exactly, but I am guessing that the problem
is with arguments that are held unevaluated and has nothing to do with
variable localization.  I am guessing, for example, that Module could be
dropped from this example and it still wouldn't do what was intended.
That problem can be corrected too, but it is separate issue.

> A side observation possibly of interest: If we change the code in setRules
> so that S is not first copied to symL (i.e., not "mediated") but used
> directly in the rule, the value of S does appear when the rule is examined
> using DownValues.  This seems to shed some light on Mathematica's timing --
> the value found for S_ is passed to RHS of := very early and is not held but
> treated as "raw".

I don't understand exactly what this example is either (did you perhaps
mean sym used directly, rather than S?), but if that guess is correct
then yes, rule application is a way of getting values into held expressions
and into scoping contructs like SetDelayed, both of which appear to
be needed here.

Dave Withoff
Wolfram Research


  • Prev by Date: numerical approximation to the diffusion equation in Mathematica?
  • Next by Date: normalizationFourier[]
  • Previous by thread: Re: Re: scope all wrong? in Mathematica 4.1
  • Next by thread: Re: Re: Path finding in graph theory, Lookig for your help