-2
$\begingroup$

I have used the following method and it seems to be working. Just posting here since this way seems hacky. So if anyone can point a better way.

$condition=True;
Quiet@ReleaseHold@Block[Evaluate@If[$condition,Hold@{a=10},Hold@{b=5}],{a,b}]

Note in this example I am just blocking random symbols but in my real application I am blocking built-in functions.

If $condition=True I get:

{10, b}

If $condition=False I get:

{a, 5}

$\endgroup$
5
  • 2
    $\begingroup$ Can you explain what you are actually attempting to achieve? I can't follow your example, and you yourself say that it is not very representative of what you are actually trying. $\endgroup$
    – MarcoB
    Commented Apr 26 at 14:11
  • $\begingroup$ I think explaining the real application would divert from this tiny technical piece. I just want to know if we can pass a different set of Block variables to a Block statement depending on a $condition. I mean you can as you can see from my approach but I had to Hold the Set while I Evaluate the first argument of Block and all the while muting the messages from Block as it sees its first argument dynamically change at runtime. $\endgroup$
    – user13892
    Commented Apr 26 at 14:39
  • 2
    $\begingroup$ Would it work to enclose two different Blocks in an If statement instead? The reason I'm asking for context is because this smells of an XY problem, i.e. you are asking for help not with your actual problem, but with your attempted solution, where in fact there may be a different and more direct way to solve your problem that does not require these gymnastics. $\endgroup$
    – MarcoB
    Commented Apr 26 at 14:49
  • 2
  • $\begingroup$ You mean this right? If[$condition,Block[{a=10},{a,b}],Block[{b=5},{a,b}]] $\endgroup$
    – user13892
    Commented Apr 26 at 15:03

2 Answers 2

1
$\begingroup$

While I understand that you think you're asking about just a "tiny technical piece", the semantic framing of a problem is EVERYTHING. Since you've already discovered one way to do this "tiny technical piece", why are you asking for alternatives? You must think there is a way that is more elegant with regard to your semantics. Even judging something to be "hacky" depends on the semantics. Your context may make this solution seem hacky or it may make this solution seem ingenious. With that sermon out of the way, I'll make a guess, which might be totally unhelpful--that depends on your context.

Rather than make big global conditional constructs, I usually prefer a more surgical and functional strategy. The underlying idea seems to be that you want to swap built-in symbols with your own replacement definitions based on some flag. So, why not just build that capability directly?

SwitchIt[False][sym_Symbol] := sym;
SwitchIt[True][Pi] = \[FormalA];
SwitchIt[True][Times] = LeftRightArrow;
SwitchIt[True][sym_Symbol] := Inactive[sym];

Then you can precisely control your transformations:

ReleaseHold[Hold[43 Pi] /. {Times -> SwitchIt[True][Times]}]
(* 43 \[LeftRightArrow] \[Pi] *)

$condition = True;
ReleaseHold[Hold[43 Pi] /. {Times -> SwitchIt[$condition][Times], Pi -> SwitchIt[$condition][Pi]}]
(* 43 \[LeftRightArrow] \[FormalA] *)

$condition = True;
Operate[SwitchIt[$condition], a b c]
(* a \[LeftRightArrow] b \[LeftRightArrow] c *)

$condition = True;
Operate[SwitchIt[$condition], a + b + c]
(* Inactive[Plus][a, b, c] *)

$condition = True;
ReleaseHold[Hold[43  Pi] /. {x_Symbol :> SwitchIt[$condition][x]}]
(* Inactive[Hold][43 \[LeftRightArrow] \[FormalA]] *)

And specifically for your toy example:

SwitchIt[True][a] = 10;
SwitchIt[True][b] = 5;

$condition = True;
{a, b} /. {a -> SwitchIt[$condition][a], b -> SwitchIt[! $condition][b]}
(* {10, b} *)

$condition = False;
{a, b} /. {a -> SwitchIt[$condition][a], b -> SwitchIt[! $condition][b]}
(* {a, 5} *)

Or using Block,

Block[
  {a = SwitchIt[$condition][a], b = SwitchIt[! $condition][b]},
  {a, b}]
$\endgroup$
0
$\begingroup$

Here are few alternatives, using what I think I've seen called an injector pattern (which I just found in this answer by @Mr.Wizard and might be considered a duplicate):

$condition = True;
If[$condition, Most, Rest][Hold[{a = 10}, {b = 5}]] /. 
 Hold[v_] :> Block[v, {a, b}]
(*  {10, b}  *)

$condition = True;
If[$condition, Most, Rest][Hold[a = 10, b = 5]] /. 
 Hold[v___] :> Block[{v}, {a, b}]
(*  {10, b}  *)

$conditions = {True, False, True};
Pick[Hold[a = 10, b = 5, c = 7], $conditions] /. 
 Hold[v___] :> Block[{v}, {a, b, c}]
(*  {10, b, 7}  *)

Injecting with a Function:

$conditions = {True, False, True};
With[{code = Function[,
    Block[{##}, {a, b, c}],
    HoldAll
    ]},
 Pick[Hold[a = 10, b = 5, c = 7], $conditions] /. Hold[v___] :> code[v]
 ]
(*  {10, b, 7}  *)
$\endgroup$

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