Copyright (C) 1997 Rich Neidinger, John Swallow, and Todd Will.  Free for
distribution to college and university instructors for personal,
non-commercial use.  If these notebooks are used in a course, the authors
request $20 per student.

23. Contexts and Packages

Last revision:  October 16 1996

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.

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]