2
$\begingroup$

Sorry if this is kind of a noob question but I'm wondering what the best-performing approach is to the following: I'd like to define several local constants in the body of a function, each of which depends on the value of the previous one(s) in an arbitrarily complicated way. My understanding is that e.g. when doing this with a single constant, the best thing to do is use With:

f[args___]:= With[{const = (* something *)},
  (* body where the value of const may be used many times over *)
]

As I understand it, this is better (per the documentation for With) than using Block or Module more or less because Mathematica does not have to set up a local environment where the value of const may be repeatedly updated throughout the evaluation.

Now, suppose we want to write a function where there will be multiple local constants, each of which depends on the previously defined ones and each of which is used many times throughout evaluation. A very straightforward way to implement this would be to use one Block where we can mindlessly give names to all our constants and compute them in order, at the expense of forcing Mathematica to waste time pretending that these constants might be updated at some point in the evaluation of the function when in reality they won't. It seems that the solution using With forces us to use many nested With statements:

f[args___]:= With[{const1 = (* something *)},
  With[{const2 = (* computation using const1 any number of times *)},
    ...
      (* body where the values of all constants may be used many times over *)
    ...
  ]
]

Does anyone know whether there is some point (e.g. some number of such nested statements) where the overhead of nesting them like this might become more expensive than just using a flat Block structure? Or is it always advantageous in these situations to use With, however many nestings might be required? I would try to test this myself but I'm not confident I understand what's going on well enough to cover the appropriate ranges of test cases and to interpret the results.

$\endgroup$
7
  • $\begingroup$ Are you actually running into performance issues? $\endgroup$
    – lericr
    Commented Apr 26, 2023 at 21:02
  • $\begingroup$ I don't have technical insight into implementation to offer a definitive answer to the question, but I can offer my own guidance: use With unless you're forced into using something else or unless the specific circumstances genuinely do call for Block or whatever. Sometimes, you'll end up with several layers of nesting, but in some sense that's when With is even more important, because it does more to protect you from certain errors than the others do. $\endgroup$
    – lericr
    Commented Apr 26, 2023 at 21:06
  • 3
    $\begingroup$ Nested Withs might provide a small performance benefit, but they are a maintenance nightmare: Code is much more cumbersome to debug because it has to be heavily refactored before one can be evaluated again step by step. At least for most of my tasks I get way better performance boost by Compile-ing the most performance critical piece of code. (Btw., I think the C-compiler is way better in exploiting constness than the Mathematica kernel -- even without declaring things as const. Simply because it is given way more time to mull over this.) $\endgroup$ Commented Apr 26, 2023 at 22:29
  • 2
    $\begingroup$ You may also consider to use LetL by Leonid Shifrin: mathematica.stackexchange.com/a/10451. $\endgroup$ Commented Apr 26, 2023 at 22:32
  • 6
    $\begingroup$ With supports the (undocumented) syntax With[{x=3},{y=x^2},{z=x+y},...] $\endgroup$ Commented Apr 27, 2023 at 0:35

0

Your Answer

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