3
$\begingroup$

I am quite confused about Context. I have a long semi-manual signal processing task. I already did that for one signal and I need to do it for another one. I want to preserve all variables for both signals as their calculation is lengthy. So I thought of using Context for that (else, I would need to make new variables with new names and that would mean to change all the code.

Now, if I do the following sequnce of commands:

$Context

returns:

Out[1]= "Global`"

Starting a new context:

Begin["ContextA`"]
a = 3;
b = 33;
c = a + b;
{a, b, c}
End[]

returns:

"ContextA`"

{3, 33, 36}

"ContextA`"

Which context am I now in?

$Context

returns

Out[8]= "Global`"

Try:

a

returns:

Out[9]= a

Try

{ContextA`a, ContextA`b, ContextA`c}

returns

Out[11]= {3, 33, 36}

Up to now everything is as expected. But the problem starts when I want to go back to the context ContextA:

Begin["ContextA`"]
$Context

returns:

"ContextA`"

"ContextA`"

Correct but:

a

returns unexpectedly

Out[14]= a

Then

b

Makes more confusion by returning:

Out[15]= 33

the rest is as I was expecting:

c

returns

Out[16]= 36

So let's try again

a

returns

Out[17]= a

try something else

d = 123;
End[]

gives

Out[19]= "ContextA`"

Verify, i am out:

In[20]:= $Context

Out[20]= "Global`"

Where is d?

In[21]:= d

Out[21]= d

In[23]:= {ContextA`a, ContextA`b, ContextA`c, ContextA`d}

Out[23]= {3, 33, 36, 123}

Try again:

In[24]:= Begin["ContextA`"]
$Context

Out[24]= "ContextA`"

Out[25]= "ContextA`"

In[26]:= a

Out[26]= a

In[27]:= ContextA`a

Out[27]= 3

What is wrong with this? Why cannot I access a when I switch to the ContextA? What is the proper way to switching back to a given context to continue to work in that context so that I have access to all expressions that i previously created in that context?

At this point, I read the suggested posts this and this which seem to indicated that the way a behaves should be correct, but then, why the other variables are not behaving the same way?

Anyway, if I had to prepend ContextA to all variables after entering the context, then this is completely useless for my purpose as it is the same as having to rename all the variables. Is there a way to tell Mathematica, "Hey, now we are working with variables in ContextA so when I write a, you will interpret that as "ContextA`a"!"?

$\endgroup$

2 Answers 2

4
$\begingroup$

The issue is caused by your 8th input, namely:

a
Out[8] = a

If you remove this line, you'll find that a behaves as expected.

But why is that? The reason has to do with $ContextPath, and how it interacts with $Context. In essence, the problem boils down to how symbols are created/found:

  1. If the symbol is of the form someContext`symbol, the symbol is always taken from/created in someContext`
  2. If the symbol is of the form `symbol, the symbol is always taken from/created in the current $Context. (symbols of the form `subContext`symbol are taken to refer to a symbol in the subcontext context`subContext` of the current $Context)
  3. Otherwise, the symbol is looked for in the contexts in $ContextPath in order. If it is found in any of them, it is taken from there. If it is not, the symbol is taken from/created in the current $Context. This priority is mentioned in the last sentence here (emphasis mine):

Conflicts can occur not only between symbols in different packages, but also between symbols in packages and symbols that you introduce directly in your Wolfram Language session. If you define a symbol in your current context, then this symbol may become shadowed by another symbol with the same short name in packages that you read in. The reason for this is that the Wolfram Language searches for symbols in contexts on the context search path before looking in the current context.

We can now take a look at a simplified example (make sure to enter each line in a separate cell):

Begin["ContextA`"]
(* Out[1]= "ContextA`" *)

$ContextPath
(* Out[2]= {"System`", "Global`"} *)

a = 5
(* Out[3]= 5 *)

Context@a
(* Out[4]= "ContextA`" *)

End[]
(* Out[5]= "ContextA`" *)

ContextA`a
(* Out[6]= 5 *)

a
(* Out[7]= a *)

Begin["ContextA`"]
(* Out[8]= "ContextA`" *)

Context@a
(* Out[9]= "Global`" *)

Context@ContextA`a
(* Out[10]= "ContextA`" *)

Context@`a
(* Out[11]= "ContextA`" *)

The problem now starts with input 7: We access a, which causes a to be created in the current context Global` . If we now switch back to ContextA` , this symbol is still in a context in $ContextPath, which will always be found before the symbols in the current context.

To work around this, you can:

  • use symbols of the form `symbol (as shown in line 11 above)
  • modify $ContextPath to include your current context (remember to reset it again if you want)
  • use BeginPackage/EndPackage instead which come with automatic $ContextPath management. Note however that they will also leave the created context on $ContextPath afterwards, and clear out $ContextPath while you're between BeginPackage[] and EndPackage[].
$\endgroup$
4
  • $\begingroup$ Oh there was the dog hiding, the fact that I accessed a in the context that was in the ContextPath but the others I did not. Now a followup, not sure how to ask: Why does typing a and executing "create" a. What does that even mean in this sense to "create". I understand (though superficially) things like a=1 or a:=b etc there is assignment but a does not assign anything, so why suddenly it "pops up" into the memory world? $\endgroup$
    – atapaka
    Apr 5, 2023 at 14:59
  • 1
    $\begingroup$ @atapaka Whenever you enter any expression into the front-end and evaluate it, the box version (can be seen via Cell > Show Expression) is sent to the kernel, which uses MakeExpression to turn this into a symbolic expression to be evaluated (strictly speaking, this is the place where symbols are created, effectively using something like Symbol). This allows the kernel to uniformly handle any input: It will always be a combination of numbers, strings & symbols, each symbol having a name and a context. [cont.] $\endgroup$
    – Lukas Lang
    Apr 5, 2023 at 16:02
  • $\begingroup$ [cont.] This means that even the simplest case of evaluating a needs to create the symbol a. Maybe it also helps to think about a slightly less extreme example like list = {a,b} - even without any assignment, both a and b need to exist as symbols. Otherwise, what would list contain? Or take Context[a] or SymbolName[a], where clearly, a needs to be a symbol. $\endgroup$
    – Lukas Lang
    Apr 5, 2023 at 16:03
  • $\begingroup$ So, put differently: Simply "mentioning" a symbol in any way will create it (in the current/specified context). As mentioned, this happens during the MakeExpression step (for notebooks)/the parsing step (for package files). Only then is the code evaluated and any assignments etc. are performed (you'll note that this is a completely separate step from symbol creation). $\endgroup$
    – Lukas Lang
    Apr 5, 2023 at 16:05
3
$\begingroup$

Walking through step by step:

$ContextPath (* this is the path that Mathematica searches when looking for the definition of a symbol*)

{"System`", "Global`"} <- this means that it will first look in System and then in Global.

$Context (* this is the context in which new symbols will be put*)

Global` <- any new symbol will be in the Global context

Begin["ContextA`"] (* this changes $Context, but NOT $ContextPath*)

ContextA`

$Context

ContextA`

$ContextPath

{"System`", "Global`"}

a = 3;
Context[a]

ContextA` <- expected

End[]

ContextA` <- this tells us which context we just left

$Context

Global` <- new symbols will be in this context

$ContextPath

{"System`", "Global`"} <- still the same, this has never changed

a; (* MMA will start looking in its context path for this symbol*)
Context[a] 

Global`

At this point, Mathematica started looking for the symbol a in its context path, but it didn't find it. Therefore, it will create a new symbol in the current context, which is Global. However, the a in ContextA is still remembered:

ContextA`a

3

Okay, so, the question is how do we add ContextA to the context path? That's what BeginPackage (and the associated EndPackage) are for. See the docs for $ContextPath.

$\endgroup$
4
  • $\begingroup$ Guess I was a bit slow. $\endgroup$
    – lericr
    Apr 4, 2023 at 20:25
  • $\begingroup$ I'm a bit amazed how we all managed to answer within a minute of each other, all with quite lengthy texts :) $\endgroup$
    – Lukas Lang
    Apr 4, 2023 at 20:32
  • $\begingroup$ I think they were all submitted within 30 seconds $\endgroup$
    – Jason B.
    Apr 4, 2023 at 20:32
  • $\begingroup$ @JasonB. Now the same thing is happening with the comments... $\endgroup$
    – Lukas Lang
    Apr 4, 2023 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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