# Functions that creates symbol in a specific context

I'm trying to make a function f that takes a symbol, a value, and a context, and creates the symbol in the requested context and assigns it the passed value. The obvious doesn't work. I.e.:

Attributes[f]={HoldAllComplete};
f[symbol_,value_,context_]:=(Begin[context];Set[symbol,value];End[])


Creates the symbol in the current context, as opposed to the one that is passed as an argument. This seems to happen because the FrontEnd, as soon as it sees f getting evaluated, creates the symbol in the current context despite HoldAllComplete. I tried adding Remove[symbol] to the function but that doesn't work. Any thoughts?

-
I should clarify that I really need to pass the symbol, not the symbol's name. I realize it can be done when passing the symbol's name, but I can't use that approach because it would break a lot of existing code. I realize that I can overload the function and have a legacy version that takes the symbol and does not allow contexts, and one that takes in strings and does allow for contexts, but ideally I would like to avoid such a hack. –  Mohammed AlQuraishi Apr 4 '13 at 18:47

The problem is that if you pass a symbol, it will be created already during the parsing stage, when you pass it, in the current context. Therefore I suggest to pass its string name instead. This function will do the job:

ClearAll[f];
f[symbolName_String, value_, context_] :=
Block[{$ContextPath}, BeginPackage[context]; ToExpression[ symbolName, StandardForm, Function[name, Set[name, value], HoldAll] ]; EndPackage[] ]  for example f["a", 10, "Test"] Testa (* 10 *)  If you still want to pass a symbol, you can use this: ClearAll[f]; f[symbol_, value_, context_] := With[{set = MakeBoxes[symbol = value]}, Block[{$ContextPath},
BeginPackage[context];
ReleaseHold[MakeExpression@set];
EndPackage[]]];


which is a version of the code I used here. But be aware that you will also create the symbol symbol in the current working context, so you may additionally use Remove to remove it.

So, for example:

f[a, 20, "Test"]
Testa

(* 20 *)

-
Thanks for the suggestion but this won't work for my needs. See the comment that I added to the question. –  Mohammed AlQuraishi Apr 4 '13 at 18:49
@OleksandrR. The symbol with the same name may exist in some other context currently on the $ContextPath, in which case that one will be used and assigned a value - which is obviously not what one would like here. The use of BeginPackage and EndPackage effectively allows to reset the $ContextPath to just {"MyContext","System"}, which solves this problem. –  Leonid Shifrin Apr 4 '13 at 19:24
@MohammedAlQuraishi I added a symbol-based version, see my edit. –  Leonid Shifrin Apr 4 '13 at 19:29
@LeonidShifrin: Great, thank you! –  Mohammed AlQuraishi Apr 5 '13 at 3:02
@Mr.Wizard I will use your usual reply: "great minds think alike" :) –  Leonid Shifrin Apr 5 '13 at 15:41

I believe this is what you want:

f[symname_String, value_, context_] :=
(Begin[context];
With[{s = Symbol[symname]}, Set[s, value]]; End[])


Then use it like this:

 f["myvar", 4, "MyContext"]


Verify:

? MyContextmyvar


Hope that helps

-
Really? Maybe if you do a ClearAll[f], or restart a new, fresh Mathematica session? or give the function another name? I am guessing your old definition for f is in conflict with the one I propose. Notice the idea is the same as the one by Leonid, give the name as a string "myvar" instead of myvar –  MaTECmatica Apr 4 '13 at 18:46
It does work for me. But, invoking f twice for the same symbol will produce an error. You need to take Leonid's approach of using ToExpression rather than Symbol if you want to avoid that. –  Oleksandr R. Apr 4 '13 at 18:56
@QuantumMathematica Yes indeed, on a fresh kernel it does work. –  Leonid Shifrin Apr 4 '13 at 19:33

I believe this meets your specification:

Attributes[f] = {HoldAllComplete};

f[symbol_, value_, context_] :=
ToHeldExpression[context <> SymbolName@Unevaluated@symbol] /. _[x_] :> (x = value)

-