Refering to global variables inside modules



How do I refer to global variables inside modules if the same name is used for a local one? In code, I want that

proc[a_] := Module[{b},
  b = a;
  {"b" -> b}
b /. proc[1]

returns 1. Here "b" is to be replaced by the properly escaped global variable name.


Posted 2013-12-21T16:36:16.410

Reputation: 1 600



Using Symbol is one way:

b = 10;
 b = 5;
(* Out: 10 *)

Your example:

proc[a_] := Module[{b}, b = a;
  {Symbol["b"] -> b}]
b /. proc[1]
(* Out: 1 *)

C. E.

Posted 2013-12-21T16:36:16.410

Reputation: 67 448


Using Symbol["b"] as illustrated by Anon works because the renaming by Module takes place before evaluation, but this is not robust in the sense that it is not equivalent to the Symbol b; it is only an expression that evaluates to b. Consider what happens if we try to make an assignment to this expression:

ClearAll[proc, b]
proc[a_] := Module[{b = a}, Symbol["b"] = b]
Set::write: Tag Symbol in Symbol[b] is Protected. >>

The simplest answer is: use a different Symbol name so that there is no conflict. This is not merely a tautology. Ultimately any solution will resolve to this, as using a different Symbol name is the method by which Module itself operates. Even the code above works by this method, though not robustly. Observe:

f[a_] := Module[{b = a}, Hold[Symbol["b"] = b]]

Hold[Symbol["b"] = b$289]

The explicit appearances of b in the Module have been replaced with b$289, such that when Symbol["b"] evaluates to b there is no conflict.

We can use this same type of renaming to prevent the collision in the first place. (See Enforcing correct variable bindings and avoiding renamings for conflicting variables in nested scoping constructs for an understanding of the automatic renaming I shall use.)

First an illustration:

ClearAll[f, b]
f[a_] := With[{bb = b}, Hold @ Module[{b = a}, Hold[bb = b]]]
Hold[Module[{b$ = 7}, Hold[b = b$]]]

I added a second Hold so that we can observe what happens to the Module: all appearances of the localized symbol are replaced with b$. This is separate from the renaming that takes place because of the Module itself. Continuing the evaluation:

Hold[Module[{b$ = 7}, Hold[b = b$]]] // ReleaseHold
Hold[b = b$580]

We can combine this automatic renaming within scoping constructs with an undocumented With syntax that holds substitution values unevaluated to create a robust method:


proc[a_] :=
  With[{bb := b},
    Module[{b}, b = 2 a; bb = b]

Now the assignment is made to global symbol b even if a prior assignment exists:

proc[3]; b
proc[7]; b



Posted 2013-12-21T16:36:16.410

Reputation: 259 163


The problem is the Module's local symbols overshadows the global symbols while the Module is being evaluated. One can see this by this example

b = 1;
foo[] := Module[{b = 3},

What do you expect foo[] will print? Will it print 3 1 or 3 3 ?

It prints 3 3. The Globalb has been overshadowed by the local b, even though the Global context was added explicitly.

One way is to explicitly give different context to the global b, like this

my`b = 1;
foo[] := Module[{b = 3},

Now it prints 3 1

Another way, is to add a context to each local symbol, like this

b = 1;
foo[] := Module[{foo`b = 3},
  Print[Global`b];  (* or just  b here *)

Now it prints 3 1 also. But one can argue that the whole point of using a Module is that one does not have to do this.

The button line is: To be safe, do not access (even if for read only) any global variables. The notebook interface tells by the color of the symbols which symbol is local and which is not.


Posted 2013-12-21T16:36:16.410

Reputation: 92 661


As others have mentioned I think the best solution is to use a different name for the module local variable in this case. There is another possibility to achieve what you want that I wanted to show just for completeness. Whether it is a useful solution to your problem depends very much on what you actually want to achieve, though...

proc[a_] := Module[{b}, b = a; {s_Symbol?(SymbolName[#] == "b" &) -> b}]

the trick is to use a pattern which will match any symbol for which SymbolName will return "b". This will of course also replace symbols with other contexts than Global`:

b /. proc[1] 
OtherContext`b /. proc[1]

of course you could use additional conditions to only replace symbols of explicitly defined contexts, e.g.:

proc[a_] := Module[{b},
   b = a; 
   {s_Symbol?(And[SymbolName[#] == "b",Context[#] == "Global`"] &) -> b}

of course that might fail/not do what is expected if used within a package or notebook with another context than Global`...

Albert Retey

Posted 2013-12-21T16:36:16.410

Reputation: 22 455