Overall, I am looking for a way to prevent the evaluation of the body of Manipulate until the controls meet a certain condition.

For example, consider the following.

(*big code*),
 {{x, Null}, {1, 2}, PopupMenu},
 {{y, Null}, {3, 4}, PopupMenu},
 TrackedSymbols :> True]

(* big code*) depends on x and y and is not just one function, but large, computationally expensive code containing variable assignments and functions. Because the body of Manipulate is computationally expensive, I of course, do not want it to run if either x is Null or y is Null.

I tried using If and SynchronousUpdating -> True as below.

 If[x == Null || y == Null, {x, y}, #] &@(* big code*),
 {{x, Null}, {1, 2}, PopupMenu},
 {{y, Null}, {3, 4}, PopupMenu},
 TrackedSymbols :> True, SynchronousUpdating -> True]

However, something is fishy here. First, when running the code for the first time, x and y are both Null, so the code should run very fast. I get the correct output, but the code is slow, which makes me think (* big code*) is still being read when it shouldn't be. Second, if I then change x while keeping y in its default Null value, I get the correct output, but once again, the code runs slowly. Finally, when I make both x and y not Null, the output is garbled.

I feel there should be a better way of doing what I want anyway. Any thoughts?

I just want the body of Manipulate to be touched in no way until the controls meet a certain condition.


Doing all of what @lericr mentioned in the comments solves this problem.

  • $\begingroup$ can you modify the definition of expensiveFunct to only fire on numbers? Something like expensiveFunct[x_?NumericQ, y_?NumericQ] := <expensive code>; expensiveFunct[___] := $Failed $\endgroup$
    – Jason B.
    Dec 2, 2022 at 21:37
  • $\begingroup$ @JasonB I have undated my post. To be clear, it isn't one function. It is a large chunk of code containing many functions and variable assignment. $\endgroup$ Dec 2, 2022 at 21:46
  • 2
    $\begingroup$ If is a special form. It holds its arguments (after the initial predicate) unevaluated. But you're applying a functional form (If[...,...,#]&), so the big code stuff is being evaluated. You need to put the big code stuff inside the If. Another problem is you're using == with Null, which I don't think will ever evaluate to a boolean unless the left hand side is Null. So, you either need to use === or you need to add a fourth argument to your If. $\endgroup$
    – lericr
    Dec 2, 2022 at 21:53
  • $\begingroup$ As an illustration of @lericr 's comment compare a = 1; If[a == 1, 1, Pause[2]] // AbsoluteTiming with a = 1; If[a == 1, 1, #] &[Pause[2]] // AbsoluteTiming. However If[a == 1, 1, #; 2] &[Unevaluated[Pause[2]]] // AbsoluteTiming leads to the same result as placing the Pause inside the If $\endgroup$ Dec 2, 2022 at 22:00
  • 1
    $\begingroup$ Thanks to @lericr and all others. These comments solved my problem. $\endgroup$ Dec 2, 2022 at 22:33


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.