5

Consider the following code:

Begin["mycontext`"];
myvar = 7;
Print[Context[]];
Print[Context[myvar]];
End[];

with the output

mycontext`

mycontext`

Now consider the same code inside a Do-loop:

Do[
Begin["mycontext`"];
myvar = 7;
Print[Context[]];
Print[Context[myvar]];
End[];
, {i,1,2}];

which produces the output

mycontext`

Global`

mycontext`

Global`

What is going on here? Why is myvar considered to be in "Global`"? Even if I force the definition to

mycontext`myvar = 7;

it will still be considered to be global. How do I use contexts inside loops correctly?

The whole point of doing this is the following: I have several similar configuration files (that only contain variables) in "./folder1/config.m" and "./folder2/config.m" etc. which I have to apply some manipulations to. My idea is to loop over all folders, use a local context, Get["./folderX/config.m"], write some new values for the variables, and then Save["./folderX/config.m", "mycontext`"].

Example config.m

currentfolderstuff = 0;
anotherfolderstuff = 0;

What I want to do

Do[
(* some sophisticated stuff with many variable names that will pollute my local context *)
a = i^2 + 7^2 + ...;
b = somefunc[i];
Begin["mycontex`"];
Get["./folder"<>ToString[i]<>"/config.m"];
currentfolderstuff = a;
anotherfolderstuff = b;
Save["./folder"<>ToString[i]<>"/newconfig.m", "mycontext`"];
End[];
, {i,1,2}];
image357
  • 517
  • 3
  • 15
  • 2
  • I do not full understand your update, and how these config files are related to contexts. Perhaps a explicit example will help. Get is affected by Begin because Get needs to parse the contents of a file. Regarding config files: I recommend storing config data as associations instead of code (i.e. several assignment lines). – Szabolcs Apr 10 '17 at 14:51
  • @Szabolcs: I don't have any influence in designing the config files. They are used in an external MMA program which I am trying to configurate. – image357 Apr 10 '17 at 15:02
  • You could use BeginPackage instead of Begin to ensure that $ContextPath only has your context while reading the file (see here), and explicitly specify the context on currentfolderstuff, i.e. write mycontext`currentfolderstuff in your loop. I have not tested this, so there might be a little mistake in there somewhere. – Szabolcs Apr 10 '17 at 15:10
  • 2
    Actually, instead of using BeginPackage, just enclose the Get in Block[{$ContextPath = {"mycontext`", "System`"}, $Context = "mycontext`"}, Get[...]]. BeginPackage does other things too which you do not want. – Szabolcs Apr 10 '17 at 15:12
  • @Szabolcs: Awesome! It's working. But why? How does Block[...] ensure, that "mycontext`currentfolderstuff" outside of Block[...] gets recognized to be not in "Global`" (as opposed to the version without Block[...]). – image357 Apr 10 '17 at 15:22
  • @Szabolcs: For clarification: I used "Begin[...]; Block[..., Get[...]]; mycontext`currentfolderstuff = a; ... End[];" This works. However just using "Block[..., Get[...]; mycontext`currentfolderstuff = a; ...];" without any Begin statement does also work. – image357 Apr 10 '17 at 15:36

1 Answers1

9

Begin["mycontext`"] affects the parser, not the evaluator.

These are separate expressions:

Begin["mycontext`"];
myvar = 7;
Print[Context[]];
Print[Context[myvar]];
End[];

They get parsed and evaluated one by one. Once Begin["mycontext`"]; is evaluated, the new context applies to all subsequent lines.

This is a single expression:

Do[
Begin["mycontext`"];
myvar = 7;
Print[Context[]];
Print[Context[myvar]];
End[];
, {i,1,2}];

It gets parsed as one unit, an evaluation begins only afterwards. Begin["mycontext`"]; does not get a chance to get evaluated before the parsing of myvar.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • Ok, so how do I fix that? How do I force MMA to evaluate Begin[] inside a loop separately? – image357 Apr 10 '17 at 14:37
  • 1
    @Marcel In most cases trying to do this is a bad idea. Begin does not belong in a loop. Can you explain in clear terms why you want to do it? (Please edit the question instead of explaining in a comment.) – Szabolcs Apr 10 '17 at 14:38
  • 1
    @Marcel please show a line or two from your config files so that everything is clear. Since the context does not change you can begin it before calling Do and close after. – Kuba Apr 10 '17 at 14:51
  • @Kuba: Ok, I have done that. – image357 Apr 10 '17 at 15:07