4
$\begingroup$

I have a list of variables

var={v1,v2};

which I want to protect/localize during a particular operation. I have decided that I want to use Block and if I write

Block[{v1,v2},Print[4]] 

everything is fine but what I really need is to somehow implement the functionality:

Block[vars,Print[4]] 

Is there any way to achieve this?

$\endgroup$
8
$\begingroup$

Storing v1 and v2 in a variable makes it more complicated. It is better to construct custom dynamic environments based on Block, which would be closures, closed over symbolic variables you want.

Here is a generator for such environments:

withBlockedVars = Function[vars, Function[code, Block[vars, code], HoldAll], HoldAll];

Here is how you generate a particular one you need (v1 and v2 here may have global values, this doesn't matter):

myBlock = withBlockedVars[{v1, v2}]

(* Function[code$, Block[{v1, v2}, code$], HoldAll] *)

What you get is a closure, with your specific variables embedded into it. Here is how you can use it:

{v1, v2} = {1, 2};
myBlock[Print[{v1, v2}]]

(* {v1,v2} *)

If you insist on using var, you can do it like so:

myBlock = Hold[var] /. OwnValues[var] /. Hold[val_]:> withBlockedVars[val],

and then continue in the same way as above.

$\endgroup$
6
$\begingroup$

Using my bump function (horrible name, sorry) from Elegant manipulation of the variables list:

func_[bump[lst_, idx___], arg___] ^:= 
  func[#, arg] & @ Part[List @@@ Unevaluated @@ {lst}, {1}, idx]

{v1, v2} = {7, 9}; (* existing values *)

vars = Hold[v1, v2];

Block[bump[vars], Print[v1, ", ", v2]]
v1, v2

See the linked question for many other uses of this flexible function.

$\endgroup$
2
$\begingroup$

Actually, it turns out that what I was looking for was a simple use of Evaluate, i.e. the following code:

var={v1,v2};
Block[Evaluate[var],Print[4]] 

does the trick, provided there are no values assigned to v1 and v2. If that is an important consideration, the more complicated code from the other answers can be used, but for me the above simple solution proved sufficient.

As Mr.Wizard pointed out in the comments the above code allows for assignments to the variables that are only local. For example the code

var={v1,v2};
Block[Evaluate[var],v1=1;v2=2;{v1,v2}] 

returns

{1,2}

whereas

var={v1,v2};
Block[Evaluate[var],v1=1;v2=2;{v1,v2}];
{v1,v2}

returns

{v1,v2}

demonstrating that the local assignments do not affect the global variables.

Once more, as Leonid points out, if there are assignments made to the variables initially, the code fails and more elaborate solutions are needed.

$\endgroup$
  • 2
    $\begingroup$ This is not as simple as that. There are reasons that the other answers are more complex. If your variables v1 and v2 have global values, then your code would fail, while the other answers would not. $\endgroup$ – Leonid Shifrin Aug 6 '15 at 15:46
  • 1
    $\begingroup$ I guess you are trying to protect a global symbol from lasting modification. This does work, but Sequence appears superfluous; you could instead write: Block[Evaluate[var], v1 = "local";] and observe that the global value of v1 is not changed. Also you have vars where I you meant var within Block. $\endgroup$ – Mr.Wizard Aug 6 '15 at 19:28
  • $\begingroup$ @Mr.Wizard : Thanks for the corrections. I will edit to incorporate them. Nevertheless Leonid's point remains valid: We are free to do local assignements to v1 and v2 within the Block, but if we give some global values to them before the above code, it doesn't work. For me personally, that is not a problem as all the variables are undefined. $\endgroup$ – Heterotic Aug 6 '15 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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