MathGroup Archive 2010

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

Search the Archive

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



  • Prev by Date: Re: How to write reports and books in Mathematica
  • Next by Date: Re: How to write reports and books in Mathematica
  • Previous by thread: Re: Scoping with Module
  • Next by thread: Re: Scoping with Module