Scope within Context

To define some package-wide functions/variables, what approach is recommended? I tried to use contexts with the Begin function, but this failed:

Clear[fun];
fun[] := Module[{},
Begin["myContext"];
x = 1;
End[];
];
fun[]
myContextx


I would expect myContext'x to be 1, but it seems to be undefined. Why does this fragment fail, what should I do instead?

-
I gave a solution for a similar problem here, where I also discussed some of the subtleties. Note that empty Module (without localizing variables) is misleading here, and can be as well removed. –  Leonid Shifrin Sep 10 '12 at 10:49

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[testx, x]
(
Begin["test"];
x = 42;
End[];
{x, testx}
)


{42,testx}

Remove[testx, x]
Begin["test"];
x = 42;
End[];
{x, testx}


{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 Globalx into scope, which means we already have an x defined when we evaluate x=42 thus it's interpreted as Globalx=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 testSin:

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, testx}


{x,0}

This will however still put Globalx in scope, it simply does not assing a value to it. So any new call to x=somethign will assign a value to Globalx and not to testx as would normally be expected if you had done a line by line evaluation of the context switching.

-
Good observation, but I would not "multiply entities". The reason for the difference is in how expressions entered in cells in the FrontEnd are parsed. The parser makes an exception for the top-level CompoundExpression (second case), parsing line-by-line - thus this works. For the first case, it parses entire body of CompoundExpression before evaluating, and therefore the symbol x is still created in the Global  context. This has been explained also here. –  Leonid Shifrin Sep 10 '12 at 10:48
"I don't think you can start and stop a context within other evaluations" - sorry, but this is simply not the case, see e.g. this answer. It is actually this feature of dynamic control over the current context and other things affecting parsing ($ContextPath) which make the encapsulation mechanism of Mathematica much more flexible and powerful. – Leonid Shifrin Sep 10 '12 at 10:52 @LeonidShifrin I stand corrected. It is indeed because x is scoped upon its first appearance when the entire expression is first evaluated, which scopes it to global. Could you elaborate on "would not multiply entities" ? – jVincent Sep 10 '12 at 10:55 Well, I just meant Occam's razor principle, in that it is always best to describe the principle from which say 10 different observations follow, than to only describe the observations alone, which would then look like magical spells. – Leonid Shifrin Sep 10 '12 at 10:58 I actually did not first notice your statement about the impossibility of dunamically changing the current context (for which the examples apparently serve as an illustration), and so initially viewed your two examples just as empirical observations of these different behaviors, thus my comment on entities multiplication :-). – Leonid Shifrin Sep 10 '12 at 11:02 The issue here is that you haven't actually defined myContextx, just plain old x. It is possible to access global variables within a context (that's exactly what happens when you use built-in function within a package), and that is what you have done. Clear[fun]; fun[] := Module[{}, Begin["myContext"]; x = 1; End[];]; fun[]  This is undefined. myContextx (* myContextx *)  But you have set x: x (* 1 *)  To make this work, set the context explicitly in the definition of your variable: morefun[] := Module[{}, Begin["myContext2"]; myContext2x = 1; End[];]; morefun[] myContext2x (* 1 *)  - Thanks, if I understand correctly, Begin just sets/alters the $Context / \$ContextPath variables, but if I want to use the context, I have to state this explicitly. Or use @jVincent's meta programming. –  Karsten W. Sep 10 '12 at 12:01

Just for reference, the way I go now is to define a global context in my add-on package, myTool'globals' and for every package function that uses a global (package-wide) variable, I make the package function dependent on the globals package:

BeginPackage["myToolalterGlobalVar", {"myToolglobals"}];
...
`

I hope this will work out well for me.

-