Re: Scoping with Module
- To: mathgroup at smc.vnet.net
- Subject: [mg109595] Re: Scoping with Module
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Fri, 7 May 2010 06:29:48 -0400 (EDT)
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) > >