13

If we evaluate these lines one-by-one, x will be created in the context cc.

Begin["cc`"];
x = 1;
End[]

However, if we evaluate them together,

(Begin["cc`"];
x = 1;
End[])

then x will be created in Global. This is despite the following printing cc`:

(Begin["cc`"];
Print[$Context];
End[])

What is the reason for this behaviour? My guess is that contexts only matter during the parsing phase, not evaluation.

Use case: I wanted to create a palette Button that will define some symbols if they don't exist yet, in a "private" context to avoid conflict with globals. What is the preferred method to do this, other than putting all the definitions in a package file and loading them from the palette? (I'd like to keep the palette self-contained.)

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • I just read in that docs that "The interpretation of symbol names depends on context. `Begin` thus affects the parsing of input expressions." That answers my first question. The second one still stands. – Szabolcs Oct 27 '11 at 14:44

3 Answers3

18

Symbols (and their contexts) are created when parsing, not evaluation. If we use $NewSymbol we can see this in effect:

$NewSymbol=Print["Name: ",#1," Context: ",#2]&;

Print["first"];
test1;
Print["last"]

(Print["first"];
 test2;
 Print["last"])

The first one prints:

first
Name: test1 Context: Global`
last

because each line in the cell is treated as a separate input. The second one uses parentheses to force all three lines to be considered one input and prints

Name: test2 Context: Global`
first
last

from which we can see that test2 was created in the Global` context before any evaluation occurred.

I think the easiest way to work with this is to use an explicit context on your symbol: cc`x = 1.

Brett Champion
  • 8,497
  • 1
  • 27
  • 44
  • 3
    Another option that is sometimes useful is to use ToExpression to do some new parsing *during* evaluation: (Begin["cc`"]; With[{s = ToExpression["x"]}, s = 1]; End[];) – Andrew Moylan Oct 28 '11 at 00:02
  • Brett, is there any way to use `$NewSymbol` to force a symbol to be created in a specific context, and by extension not in the default one? – Mr.Wizard Oct 28 '11 at 09:10
  • @Andrew, why don't you post that as an answer? – Mr.Wizard Oct 28 '11 at 09:15
  • @Mr.Wizard probably not, since `$NewSymbol` doesn't influence what happens to that symbol during further evaluation. I was doing to do something similar to what @Andrew said. When using explicit context names becomes cumbersome, one can put everything in an .m file and read that. The way to make the palette self-contained is perhaps to use a huge string instead of an .m file, and read from that. **Unless** there's maybe some reliable notebook/front-end wizardry to include the code in the palette notebook and evaluate the definitions when the palette is loaded. – Szabolcs Oct 28 '11 at 09:37
  • @Mr.Wizard I guess this deserves a separate question. I don't have a lot of experience with the notebook and the front end. – Szabolcs Oct 28 '11 at 09:47
  • @Szabolcs actually, it has already been asked, but it was never resolved. See: http://stackoverflow.com/questions/6167406/moving-contexts-with-newsymbol-in-mathematica – Mr.Wizard Oct 28 '11 at 10:07
  • @Mr.Wizard I think it's clear from the documentation example for `$NewSymbol` using `Print` that the output of the function isn't used for creating the new symbol (otherwise all the new symbols would be `Null`.) – Brett Champion Oct 28 '11 at 15:30
3

For your second question, I refer you to this answer of mine, which effectively automates the steps you outlined (with the ParseTimeNameSpaceWrapper function). It may need more work to make it more robust, but that could be a starting point. I use this stuff myself on occasion.

Community
  • 1
  • 1
Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • `ParseTimeNameSpaceWrapper` still doesn't get around the fact that the context of symbols is decided at parse-time, i.e. if I do `ParseTimeNameSpaceWrapper[x]`, that `x` will still be interpreted as ``Global`x``, not as ``MyLocalizedContext`x``. After understanding that the context is chosen at parse-time, I think there's no other way but to force a re-parse by either putting some code in a string and using `ToExpression`, or reading it from a package (or just writing the contexts explicitly as Brett suggests, but that's a lot of work for longer code). – Szabolcs Oct 27 '11 at 16:00
  • @Szabolcs I see. Perhaps this thread might be of interest to you, regarding the parsing stage: http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/c1f4ab24db8a8542 – Leonid Shifrin Oct 27 '11 at 17:13
1

Just for reference:

(Begin["cc`"]; Evaluate[Symbol["x"]] = 1; End[])

cc`x
1
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125