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]
proc[7]
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]]
f[7]
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]]]
f[7]
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:
ClearAll[proc]
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
6
14