23. Contexts and Packages

Last revision:  April 15 1998

Although local variables and modules provide one way to organize data and protect some data from modification by certain functions, contexts and packages provide a better way to implement many of the same concepts.  In this section we introduce contexts and packages and provide examples of their use.

Mathematica operations/structures introduced: 
     context
     Global`
     System`Private`
     Contexts[]
     $Context
     $ContextPath
     Begin[]
     End[]
     BeginPackage[]
     EndPackage[]
     shadowing
     Remove[]

Contexts: Wider Scope

Recall that the appearance of the same name in two different places in code does not necessarily mean that the same variable or function is being referenced each time; the two names may in fact refer to different variables.  One primary example of this situation is when one uses local variables in a module:  the names declared local inside the module do not refer to variables with the same names defined outside of the module.  Mathematica treats the two different variables separately, even if one of the variables is undefined.  Here is an example, where we ask the value of an undefined local variable when a globally declared variable has already been defined:

Clear[x]
x = 2;
testx[] := Module[{x},x];
testx[]

Mathematica assigns numbers to each occurence of the same name so that it can internally distinguish the different references, and in the code above, Mathematica tells us with "x$n" that the "x" inside the module is "x" number "n".  More importantly, however, Mathematica does not return "2", the value of the globally declared "x".

Why would we want to use the same name for several different variables or functions?  Recall further that in the local variable case, we want to use names---descriptive ones, at that---without encroaching on the names the user of the program has already declared.  In short, we wish to reserve to ourselves, inside a program, names which the user need not know about and which will not affect any of the user's data or the user's choice of names.

Now a module is an excellent way to reserve names temporarily---while the module is running--but there are some drawbacks.  First, the variables are thrown away when the module is finished executing.  Second, suppose we have data which we would like to be separate from the user's data, shared between two certain functions, but protected from other functions.  Using modules, we would either have to make the data global (and hence lose the appropriate protections), or make the data local (in which case each function would not be allowed to reference the local data of the other).  What can we use to solve this problem?  The answer is a context.

Contexts are groupings of names (variables and functions) into categories such that variables or functions in different contexts with the same names will be distinct yet will not be discarded at the end of execution of any particular function, as local variables are.  It is interesting to notice, then, that all of the non-local variables we have been declaring thus far have been in one particular context, the global context.

Names of Contexts, Long Forms of Names

The names of contexts are distinguished from the names of variables and functions by the fact that context names must be terminated by a particular character, a backwards single quote ("`").  Hence "MyContext`" is a valid name of a context, while "MyContext" is not.  Context names are used along with the (short) name of a variable or function if it is necessary to specify the particular context in which the variable or function resides.  To do so, the context name is added as a prefix to the (short) name of the variable, yielding the variable or function name's long form.  Hence, if "x" is in context "MyContext`" has long form "MyContext`x".  The "x" defined above, outside the module, has long form "Global`x".  Note that contexts can be nested, i.e., it is possible to have a context inside a context.  If "x" is in context "MyContext`" which is a context inside the context "Con1`", then its long form would be "Con1`MyContext`x".  As the name proceeds from left to right, the name becomes progressively more specific.  One nested context of particular interest is "System`Private`", which contains all system variables, and Mathematica programmers generally refrain from declaring new names in that context.

To find a list of all current contexts, use the command "Contexts[]".

Contexts[]

Whenever contexts are referred to alone, they must be enclosed in quotation marks, because they are strings; whenever contexts are part of a long form of a variable or function name, they should not have quotation marks, because they are part of a name.  For example, to set variable "x" in context "Conx`" to "2", once should execute

Conx`x = 2

On the other hand, if one wants instead to use a context name in a context command, such as "Begin[]", used later in this section, one must execute an expression such as "Begin["Con1`"]".

Default Contexts, Context Searches

Names mentioned in code without an explicit context associated with them (such as "x") always have some context associated to them, which is called the default context.  At the beginning of a Mathematica session, the default context is "Global`", and all non-local user-created names are placed inside that context.  The default context, however, may be changed in a Mathematica program.

Mathematica's searching algorithm, which determines exactly which variable a name such as "x" refers to, works as follows.  Mathematica first looks for "x" in the default context, which is given by the value of the system variable "$Context".  If Mathematica does not find "x" in the default context, it then searches for "x" separately in each context, according to the order given in a certain list of contexts, "$ContextPath", which is called the context search path, and Mathematica stops searching as soon as it finds an occurence of "x", using the value of that particular "x".  Only if "x" is not found in any of these contexts will Mathematica determine that "x" is a new name, associated to the default context.  The scope of a particular variable, then, is always determined by the value of the default context and the context search path; a particular variable may or may not be referenced when its short name is encountered.

Let's take a look to see what the values of the default context and the context search path are.

$Context

$ContextPath

New Contexts, Declaring and Initializing Names, Packages

1: Establishing a context, Declaring with long forms

To establish a new context, we need only declare some names inside it.  There are three ways to declare a name in a context. The first way, which we now consider, is to refer to the name in the long form.  If we desire to initialize it, we may refer to the name on the left side of an assignment ("="), but we need only mention the name to have it declared.  Here are some examples.

To set up a new context "C1`", with an undefined name "x" declared inside, we could execute

C1`x;

We run "Contexts[]" again to see the addition of the context.

Contexts[]

To initialize a variable "y" in context "C1" with value 1, we then execute

C1`y = 1

The disadvantage of this first way of declaring names in a context is that long forms of names take a long time to write; in insuring that the names don't clash with other names from other contexts, we've lost the flexibility to use the names we would like, which are short.  We would like instead to instruct Mathematica that all names in a certain section of code refer to a particular context.  We move, then, to the second way to declare names in a context.

2: Using the default context to declare names

The second way to declare a name in a context is to change the default context.  When the default context is changed, all names declared in subsequent lines of code without specified contexts are placed inside this new context, and this effect remains until the default context is changed back.  In order to change the default context, we execute the command "Begin[]", with (a string containing) the context name as the parameter.  (Alternatively, one can simply assign a new string to "$Context".)  When we would like to change the default context back, we execute the command "End[]", which has no parameters.  (Alternatively, we could assign "Global`" to "$Context".)

An important fact to remember when changing contexts is that Mathematica determines the context of each name for an entire cell before it executes any statement in the cell.  Thus, issuing a command to change the context must be in a separate cell from any name which is to use the new context; otherwise, the names will be interpreted in the old context before executing the cell containing the command to change the context.

To initialize "x", "y", and "z" inside a context "Con1`", we should first execute the following:

Begin["Con1`"];

Note that this context change was in a separate cell.  Then we execute

x = 1; y = 2; z = 3;

x
y
z

Everything looks fine, no.  However, "x" was not declared  in context "Con1", if "x" was already declared at the top of the section.  Why not?  The reason is that Mathematica looked to see if "x" had already been declared, either in the default context "Con1`", or any context in the search path.  Since there had already been a "Global`x" declared, Mathematica decided that "x" was not a new name, and set "Global`x" to 1.  One might think it would determine that a "y" had already been defined (in context "C1`", but "C1`" has not been added to the context search path, so Mathematica treats the use of "y" as a new variable, and creates it in the default context "Con1`".

To dispel some of this unfortunate confusion resulting from contexts, it is useful to ask Mathematica what the context of some variable is, using the command "Context[]", which simply returns the context of the parameter.  Let's see what the contexts of "x", "y", and "z" are.

Context[x]
Context[y]
Context[z]

Before any new confusion happens, let's reset the default context back to "Global`".

End[];

The notion of using a default context as we did to declare new names in a context is, then, fraught with danger in that it is possible to make a mistake, to miss declaring a new name in a context because the name has already been used in another context which is listed in the search path.  We move, then, to the third way to declare names in a context.

3: Using BeginPackage, EndPackage to declare names

The third way is to change the default context to our new context and change the context search path so that Mathematica is not allowed to "find" any other variables or functions with the same names as the ones we are defining; then Mathematica must declare the new names within the default context.  We could do so by explicitly changing "$Context" and "$ContextPath", but Mathematica provides a simpler method, using "BeginPackage[]" and "EndPackage[]".

What "BeginPackage[s]" does is take the argument "s" (a string with a context name), set the default context to "s", and alter the context search path to be a two-element list consisting of the list "{s,"System`"}".  The command "EndPackage[]" restores the default context and the context search path back to the values they had when "BeginPackage[]" was executed---except that "s" is the added to the front of the search path.

What is the effect of using "BeginPackage[]" and "EndPackage[]"?  First, "BeginPackage[]" changes the default context and search path so that any name (which is not a system name) will necessarily refer to the new context, since the default context is the new context and the search path does not contain any other context, including "Global`".  Then, after we have created the names we want in the new context, "EndPackage[]" restores the default context and the search path, and the name of the new context is added to the search path so that we can access the variables and functions from the new context without using a long form.

As an example, let's declare a context "Con2" with three variables "x", "y", and "z".  We do not worry about their previous definitions, either in "Global`" or "Con1`", since we are using "BeginPackage[]" and "EndPackage[]".

BeginPackage["Con2`"]

Again, note that the context change command is in a line by itself.

x = 1; y = 2; z = 3;

What does "shadowing" mean in the red ink?  Mathematica is warning us that we are defining a name which has another incarnation in another context.  This is true:  there is a "Global`x".

EndPackage[]

Now there are three new variables, "Con2`x", "Con2`y", and "Con2`z".  To check, let's ask what their definitions are.

Con2`x
Con2`y
Con2`z

We can also reference these values by their short forms "x", "y", "z", because "Con2`" occurs first in the search path after "EndPackage[]":

$ContextPath

x
y
z

Undeclaring Names

Up to now, we have used "Clear[]" to erase the definitions of a name.  However, using "Clear[]" with contexts will only clear definitions---the definitions of a particular variable or function referred to by the parameter---but will not erase the "mentioning" of the name.  In other words, if "x" was defined in the context "Global`", then using "Clear[Global`x]" will still leave an "x" declared in the context "Global`".  As we have seen in situations above, we may wish to completely undeclare a name from all contexts. To do so, use the command "Remove[]".

Examples

We work through some sections of code and decipher names in several contexts.

1

Remove[tie]

BeginPackage["MyP`"]

tie[x_,y_] := x+y

EndPackage[]

The result of the preceding code is to erase all declarations of "tie" from Mathematica, to establish a context "MyP`" which has a definition of "tie[]" in it, to add "MyP`" to the context search path, and to return the default context to the original one.

Hence "tie[1,2]" should return 3, since Mathematica can find "tie[]" in one of the contexts in the search path ("MyP`"):

tie[1,2]

However, there should be no definition of "tie[]" in the global context.  We can check this:

?Global`tie

2

BeginPackage["YourP`"]

tie[x_,y_] := x*y

EndPackage[]

Now, the result should be that a new context "YourP`" is declared, with a definition of "tie[]" inside it, and "YourP`" will be added to the front  of the context search path, so "YourP`" will be the first context checked for the definition of "tie[]".  Hence executing "tie[1,2]" now should yield "2".

tie[1,2]

Let's check our definitions.

?MyP`tie

?YourP`tie

?tie

Notice that Mathematica again tried "YourP`" first, in order to find a definition for "tie[]".  The context search path should have "YourP`" in front.

$ContextPath

3

Now we look at the effect of changing default contexts on the execution of code.

We'll set the default context to "MyP`" and evaluate "tie[2,3]".

$Context = "MyP`"

tie[2,3]

We have the expected result, 5, since Mathematica checked the default context first.  We can always force Mathematica to use the definition from "YourP`" by using the long form:

YourP`tie[2,3]