How to convert String to an Expression inside Manipulate which depends on control variable

Normally, in Global context, these 2 are equivalent

eqn = "r-x";
r = -2;
Plot[ToExpression[eqn], {x, -5, 5}]

and

eqn = r - x;
r = -2;
Plot[eqn, {x, -5, 5}]

But inside Manipulate (which is a DynamicModule) and assuming r is a control variable, then these are not equivalent. There is some context or scope change that is causing this which I do not fully understand. i.e. the following do not work the same way:

Manipulate[

eqn = "r-x";
Plot[ToExpression[eqn], {x, -5, 5}],
{{r, -1, "r"}, -2, 2, .1, Appearance -> "Labeled"},
TrackedSymbols :> {r}

]

and

Manipulate[

eqn = r - x;
Plot[eqn, {x, -5, 5}],
{{r, -1, "r"}, -2, 2, .1, Appearance -> "Labeled"},
TrackedSymbols :> {r}

]

The reason this would be useful, is that one can use an InputField, to enter an equation as a String, then convert it to an Expression and use it inside Manipulate, where the equation can have in it a variable which happens to be a control variable. Here is an example:

Manipulate[
Plot[ToExpression[eqn], {x, -5, 5}],
Grid[{
{"r=", Control[{{r, -1, ""}, -2, 2, .1, Appearance -> "Labeled"}]},
{"eqn", InputField[Dynamic[eqn], String], Dynamic[eqn]}
}],
{{r, -2}, None},
{{eqn, "r-x"}, None}
] The idea is that one can enter an expression in the InputField with r in it, and then change r using the slider afterwords.

The current solution to this is shown in this Prevent interdependence of controls but it is a work around and it helps if one understands better why the above example does not produce the same result when used inside Manipulate.

Any issues with this?

Manipulate[
Plot[ReleaseHold[eqn /. Symbol[$Context <> "r"] :> r], {x, -5, 5}] // Dynamic, Grid[{{"r=", Control[{{r, -1, ""}, -2, 2, .1, Appearance -> "Labeled"}]}, {"eqn", InputField[Dynamic[eqn], Hold@Expression], Dynamic[HoldForm @@ eqn]}}], {{r, -2}, None}, {{eqn, Null}, None}, Initialization :> ToExpression["r", InputForm, Function[r, eqn = Hold[r + x], HoldFirst]]] When you evaluate, for example DynamicModule[{x = 0}, Button["Increment", ++x]] it does something similar to a Module except that the result is again wrapped in DynamicModule. So in this case it retuns (almost) the exact same expression, but in the process, the kernel creates a variable (like Module would) and stores it. Even though the front end "owns" x, the kernel has it's copy. And this copy has some local ugly unique name that guarantees no conflicts. In many dynamic updates, Mathematica simply assumes that the value the kernel has is correct, so it doesn't need to sync it and saves time. So, it just sends to the kernel the dynamic code with xs replaced by the corresponding FE`x$29whatever. Now, if your code has a line such as Symbol["x"], that won't be recognized as the symbol x until the kernel already has the code and is evaluating it. So, it simply becomes the variable x in the current context. In the version in this answer, that "r" in the current context is replaced by whatever local variable Mathematica automatically replaces r with.

Take

Module[{x = 8},
ToExpression["x+8"]
]

Now, that returns x and not 8 It could be fixed with

Module[{x = 8},
ToExpression["x+8"] /. Symbol["x"] -> x
]

16

Summary: important points

• The kernel stores DynamicModule locals with a different name
• The translation is done before the evaluation takes place. Otherwise it is simply not done
• InputField doesn't do this translation
• That's because it isn't initialized properly, it was meant to edit the input field
– Rojo
Sep 28 '12 at 15:53
• I just edited... @NasserM.Abbasi
– Rojo
Sep 28 '12 at 15:54
• As soon as you type a number in place of r, the control for r decouples from the rest and does not affect things any more. Sep 28 '12 at 15:57
• @LeonidShifrin, but if you type a number in place of r isn't it supposed to stop depending on r? If I type r back and press return it works again for me
– Rojo
Sep 28 '12 at 16:03
• You may be right. Perhaps I interpreted the question differently,I just made it possible to control the value of r either in the InputField or by the slider - which is probably not what was asked. Sep 28 '12 at 16:05