Re: Scoping with Module
- To: mathgroup at smc.vnet.net
- Subject: [mg109660] Re: Scoping with Module
- From: Patrick Scheibe <pscheibe at trm.uni-leipzig.de>
- Date: Tue, 11 May 2010 06:25:57 -0400 (EDT)
Hi,
Thanks Leonid for your answer.
From the point of a user I find it very hard to explain to a newbie
(who started to see the usefulness of lokalized variables) why this
works
sol = First@
NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y[x], {x, 0, 30}];
func[x_] = y[x] /. sol;
Plot[func[x], {x, 0, 30}]
while this doen't
Module[{sol, y, x, func},
sol = First@
NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y[x], {x, 0, 30}];
func[x_] = y[x] /. sol;
Plot[func[x], {x, 0, 30}]
]
Additionally, nothing prevents you from doing something like this
t$ = 1;
Module[{f, g, t},
g[t_] := Sin[t];
f[t_] = g[t];
DownValues[f]
]
Out[2]= {HoldPattern[f$560[t$_]] :> Sin[1]}
Since most system variables are named like $... there is maybe someone
who accidently uses t$ as additional variable and gets some really
strange behavior.
The whole point is really not that important but I just thought that
there is more behind the idea of the scoping inside Module. Why
doesn't has Block this behavoir?
Cheers
Patrick
Am May 6, 2010 um 12:37 PM schrieb Leonid Shifrin:
> Hi Patrick,
>
> My understanding is that Mathematica uses aggressive variable
> renaming (more than is strictly necessary for many cases) in case it
> sees nested scoping constructs with conflicting variables (variables
> with the same name). This manifests itself in the renaming
> happening if these variables
> occur not just in the declaration lists, but also in the body, like
> here:
>
> scoping1[{a},scoping2[{b},a+b]
>
> In such cases, <b> will be often renamed to something like b$ even
> before the actual binding happens,
> for example:
>
> In[1]:= Function[a, Function[b, Print[a + b]]][c]
>
> Out[1]= Function[b$, Print[c + b$]]
>
> Note that in many cases this is not strictly necessary, but it is
> probably easier and / or more efficient to do this excessive
> renaming than to work on the case-by-case basis. Now, both Set with
> patterns and Module are scoping constructs. In your starting
> examples there are no local variables in the Module declaration , so
> no conflicts of the above type are possible. However, in this one:
>
> Module[{r},
> r = {t :> 1};
> f[t_] = t /. r;
> DownValues[f]
> ]
>
> you do have a possibility of a conflict of the above type, and so
> Mathematica renames a dummy variable in the inner scoping construct
> - <t> in f[t_] = t /. r; in this case. At the same time, <t> in the
> r = {t :> 1}; remains global since no patterns / scoping is involved
> here - thus the result you observed. In your final example:
>
> Module[{r},
> r = {t :> 1};
> r2 = r;
> f[t_] = t /. r2;
> DownValues[f]
> ]
>
> while the situation looks pretty similar from the evaluation
> viewpoint, <r> does not appear inside the definition f[t_] = t /.
> r2; lexically (this happens only dynamically), and for lexical
> scoping constructs (at least as they exist in Mathematica) this
> makes all the difference. At the time of variable name conflict
> resolution (this is before any code inside Module starts to
> execute), Mathematica can no longer sense any danger, and thus no
> renaming happens.
>
> I don't know whether this behavior should be sonsidered satisfactory
> or not, since it is certainly not very intuitive. I'd say that it's
> still ok: when we take a line like f[t_] = t /. r;, we should treat
> <t> as a local lexically scoped variable (the fact that it evaluates
> to global <t> is related to evaluation, not scoping). Therefore,
> there is generally no guarantee that injecting there r = {t :> 1};
> (which is defined outside the scope of Set in f[t_] = t /. r;) will
> work. I think that our puzzlement originates from mixing scoping and
> evaluation. From the fact that Set evaluates the r.h.s and uses
> global values of <t> for entries of <t> on the r.h.s. (this is what
> we are used to from our experiences of working with global
> variables), we subconsciously expect that this is true for all
> entries of <t> on the r.h.s, while this is only guaranteed for non-
> lexical entries of <t> - those that were not explicitly (lexically),
> but rather dynamically, present in the code before evaluation
> started. The problem is made worse by the fact that in many common
> cases it does work (like the case of global variables and no
> surrounding scoping constructs).
>
> The bottom line is that IMO the construct you looked at is not
> reliable from the start in that it attempts to do scope engineering
> and the results are then necessarily dependent on the details of
> Mathematica internal implementation of lexical scoping constructs.
> Then it is probably a matter of taste whether or not to use
> constructs like this. Personally, I do it from time to time for my
> own purposes, but I would hesitate to put them into "production"
> code. Besides, I believe that in most cases there exist more
> reliable alternatives.
>
> Regards,
> Leonid
>
>
>
> On Thu, May 6, 2010 at 12:52 PM, Patrick Scheibe <pscheibe at trm.uni-leipzig.de
> > wrote:
> Hi,
>
> I cannot explain the following behaviour of Module. Maybe someone else
> can:
>
> in the global scope
>
> f[t_] = t;
> DownValues[f]
>
> results in {HoldPattern[f[t_]] :> t} as expected. Simply wrapping it
> with Module, without
> making f lokal does not change this behaviour.
>
> Module[{},
> f[t_] = t;
> DownValues[f]
> ]
>
> results still in {HoldPattern[f[t_]] :> t}.
> Say I want to replace the right side of the definition with a rule
>
> r = {t :> 1};
> f[t_] = t /. r;
> DownValues[f]
>
> and we get {HoldPattern[f[t_]] :> 1}
>
> Module[{},
> r = {t :> 1};
> f[t_] = t /. r;
> DownValues[f]
> ]
>
> still the expected result {HoldPattern[f[t_]] :> 1}
>
> Now (sorry for the lengthy introduction) making r lokal
>
> Module[{r},
> r = {t :> 1};
> f[t_] = t /. r;
> DownValues[f]
> ]
>
> and we get {HoldPattern[f[t$_]] :> t$}. The Pattern t_ was renamed
> before the replacement could act.
> Using the local variable r to set a global r2 and it's working again.
>
> Module[{r},
> r = {t :> 1};
> r2 = r;
> f[t_] = t /. r2;
> DownValues[f]
> ]
>
> So there must be at least one thing about Module I did'nt understand.
> I thought the main difference between Block
> and Module is the lexical scoping!? But the only thing which was
> renamed is the lokal usage of r.
> Any ideas?
>
> Cheers
> Patrick
>
> 7.0 for Mac OS X x86 (64-bit) (February 19, 2009)
>
>