Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
    
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
add comment

3 Answers

up vote 5 down vote accepted

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`"]
Test`a

(* 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`"]
Test`a

(* 20 *)
share|improve this answer
    
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
2  
@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
1  
@Mr.Wizard I will use your usual reply: "great minds think alike" :) –  Leonid Shifrin Apr 5 '13 at 15:41
show 1 more comment

I believe this meets your specification:

Attributes[f] = {HoldAllComplete};

f[symbol_, value_, context_] :=
 ToHeldExpression[context <> SymbolName@Unevaluated@symbol] /. _[x_] :> (x = value)
share|improve this answer
add comment

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:

? MyContext`myvar

Hope that helps

share|improve this answer
    
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
1  
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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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