Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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[]
myContext`x

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

share|improve this question
1  
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

3 Answers 3

up vote 4 down vote accepted

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.

share|improve this answer
    
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
1  
"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 myContext`x, 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.

myContext`x  
(* myContext`x *)

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`"];
   myContext2`x = 1;
   End[];];

morefun[]

myContext2`x 
(* 1 *)
share|improve this answer
    
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["myTool`alterGlobalVar`", {"myTool`globals`"}];
...

I hope this will work out well for me.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.