3
$\begingroup$

Let's say I have file named test.m containing

test[arg1_] := ( Print[arg1];)

What is the best technique for calling test like test["value"] while preventing test from being added to the $ContextPath?

The following almost works except you must know function values ahead of time

Block[{$ContextPath,test}, Needs["test`"];test["test"]];

My question is: How do I generalize the call above to work with any number of functions without the user needing to input definitions manually?

$\endgroup$
1
  • $\begingroup$ @Nasser although I agree generally speaking everything should be in package, let's pretend the example of above is about calling functions that exist in a notebook. Now surely you are not recommending me wrap the notebook functions with Package statements simply to call a notebooks function from another notebook. At the end of the day I believe such functionality could be useful and to me it really seems like a solution is to implausible. $\endgroup$
    – William
    Commented Aug 3, 2013 at 23:12

1 Answer 1

7
$\begingroup$

As Nasser notes in a comment every Symbol has a context. You should be aware that Symbols are created during parsing. See: Local variables in Module leak into the Global context.

Alright, now that we worked out what you want here is the simplified answer:

We can perform a similar operation to BeginPackage with Block:

Block[{$ContextPath = {"runPrv`", "System`"}, $Context = "runPrv`"}, . . .]

We can combine this with Leonid's method from Is it possible to use Begin and End inside a Manipulate? to keep contexts from being fully resolved until we are ready for evaluation inside the Block. (Note that Global` Symbols are still created, as discussed above, but they will not be defined.) I believe "runPrv`" may be left out of $ContextPath in our application so long as we don't change the $Context from "runPrv`" within the Block itself. Finally we have:

SetAttributes[runPrivate, HoldAllComplete];

runPrivate[code_] :=
  With[{body = MakeBoxes @ code},
    Block[{$ContextPath = {"System`"}, $Context = "runPrv`"},
      ToExpression @ body]]

Now:

runPrivate[
  Get["test.m"];
  a = 5;
  test[a]
]

5

Global Symbols a and test remain undefined:

?a
?test

Global`a

Global`test

$\endgroup$
21
  • $\begingroup$ +1 The 2nd example is great and helps clarify. This relates strongly to the original question. How would I modify this following code so a isn't defined. Block[{$ContextPath = {"test`", "System`"}, $Context = "test`"}, a = 1;] I see in your response here mathematica.stackexchange.com/questions/24347/… you only mention 2 approaches for avoiding to define declarations int the $Context. Is there a technique that avoids pre-pending the context test` and in addition it doesn't require you run Clear[function1] first. $\endgroup$
    – William
    Commented Aug 5, 2013 at 0:13
  • $\begingroup$ @Liam You are working against the normal evaluation order, and there may be other approaches depending on what you want, such as a Cell with a unique Context, but that specific case may best be handled as Leonid showed here, e.g.: Block[{$ContextPath = {"test`", "System`"}, $Context = "test`", code = MakeBoxes[a = 1]}, ToExpression[code]] $\endgroup$
    – Mr.Wizard
    Commented Aug 5, 2013 at 0:23
  • $\begingroup$ @Liam I put this example in the question. I think perhaps we finally have what you want? $\endgroup$
    – Mr.Wizard
    Commented Aug 5, 2013 at 0:36
  • $\begingroup$ Yes. Now this isn't exactly production quality, but I'm going to assume there isn't really a better way to suppress the message like z::shdw: Symbol z appears in multiple contexts {test`,Global`}; definitions in context test` may shadow or be shadowed by other definitions. >> except with Quiet[Block[{$ContextPath = {"test`", "System`"}, $Context = "test`", code = MakeBoxes[p = 1]}, ToExpression[code]], General::shdw] or is there another way? $\endgroup$
    – William
    Commented Aug 5, 2013 at 0:40
  • $\begingroup$ @Liam I was busy updating my answer. Could you please give me an example using the current runPrivate code that produces this shadowing when run in a fresh session? $\endgroup$
    – Mr.Wizard
    Commented Aug 5, 2013 at 0:49

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.