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) > >