I'm just going to go ahead an rephrase the answer. The problem as Leonid points out is akin to shadowing. Here is a very simple example of the behavoir:
Remove[test`x, x]
(
Begin["test`"];
x = 42;
End[];
{x, test`x}
)
{42,test`x}
Remove[test`x, x]
Begin["test`"];
x = 42;
End[];
{x, test`x}
{x,42}
If you use Trace
You will see that in the second example everything is evaluated line-by-line, which means that when we get to x=42
the active context is test`
, however in the first case, we initially evaluate the CompoundExpression
which means we put Global`x
into scope, which means we already have an x defined when we evaluate x=42
thus it's interpreted as Global`x=42
.
A way to get around this is to use the fact that MakeBoxes will automatically remove any context currently in $ContextPath
while ToExpression
Automatically puts any symbol not found in any context into $Context
. Here I exclude the System`
context in order to avoid scoping for example Sin
to test`Sin
:
SetAttributes[ContextScope, HoldAll]
ContextScope[context_, expression_, exclude_: {"System`"}] :=
Block[{held},
Block[{$ContextPath = Complement[$ContextPath, {"System`"}]}, held = MakeBoxes[expression]];
Block[{$Context = context, $ContextPath = {context}},
ToExpression[held]]
]
ContextScope["test`", x = Sin[0]]
{x, test`x}
{x,0}
This will however still put Global`x
in scope, it simply does not assing a value to it. So any new call to x=somethign
will assign a value to Global`x
and not to test`x
as would normally be expected if you had done a line by line evaluation of the context switching.
Module
(without localizing variables) is misleading here, and can be as well removed. $\endgroup$