1

What is the correct way to stop all my Manipulate cells from breaking every time I issue ClearAll["Global`*"] command?

Here's an attempt below, it does not survive ClearAll["Global`*"], as the definition of clean does not get saved.

x = Range[100];
clean[x_] := Module[{y = 5}, x*5];

With[{xLocal = x, cleanLocal = clean}, Manipulate[ ListPlot[cleanLocal[xLocal], PlotLabel -> k], {k, 1, 5, 1}, SaveDefinitions -> True] ]

Here's an example of what I see (things break if ClearAll["Global`*"] is run in a different cell than Manipulate)

enter image description here

MarcoB
  • 67,153
  • 18
  • 91
  • 189
Yaroslav Bulatov
  • 7,793
  • 1
  • 19
  • 44
  • You could "localize" your definitions to the With or some other localizing construct. You could put your definitions into a context other than Global (although I suspect that's not really the kind of thing you were looking for). – lericr Nov 22 '23 at 22:43
  • What I mean by the "localizing" comment is to effectively inline things or make them anonymous: With[{xLocal = Range[100], cleanLocal = Module[{y = 5}, #*5] &}, ... ] – lericr Nov 22 '23 at 22:46
  • I used With to localize variables above, however that fails – Yaroslav Bulatov Nov 22 '23 at 22:52
  • You can localize the variables to the cell with DynamicModule via something like DynamicModule[{x, clean}, x = Range[100]; clean[x_] := ...; Manipulate[...]] – Jason B. Nov 22 '23 at 23:16
  • I guess we need to go deeper into what With actually does. With doesn't transfer the definition of x to xLocal. It replaces every instance of xLocal inside of the With with x. And, of course, it's the x that gets cleared, resulting in what you see. I put "localize" in quotes to emphasize that it was a special type of localizing. I don't see how you're going to get With to work the way you're trying. If you don't want to inline your definitions like I (and JasonB) suggested, then you need to find some other way to "hide" those definitions from the Global context. – lericr Nov 22 '23 at 23:57
  • 1
    Maybe I'll try to be even clearer... In the WolframLanguage, there are no truly local variables. Everything is global. That doesn't mean everything is in the Global context. I just mean that every symbol is accessible from anywhere--you just need to know its name (the full name including context path). The way some "localizing" constructs (like Module) work, is to just create special, difficult-to-accidentally-refer-to names. – lericr Nov 23 '23 at 00:00
  • Not to be too glib, but ClearAll["Global`*"] is a pretty blunt instrument. Perhaps use a more targeted clearing expression? – MarcoB Nov 23 '23 at 02:30
  • 1
    I don't think SaveDefinitions works the way you think it does. The saved definitions are executed when the DynamicModule is instantiated in the front end. If you change the defnition of clean while the Manipulate is running, Maniupulate will not re-execute the save definition. Since clean is global, its value is shared. Clear it, and it is undefined throughout the kernel. Copy a broken Manipulate output and paste it, and the saved definition will be executed again, restoring the original definition. Localize the symbol clean and its definition in Manipulate to protect it. – Goofy Nov 23 '23 at 03:37
  • @Goofy Ohhh! Maybe the OP was thinking that SaveDefinitions was analogous to Protect/Protected! I was so confused. Yeah, saving a symbol's definition doesn't mean that you can't later clear it. – lericr Nov 23 '23 at 05:41
  • I guess I need something like "with" that saves copy of the value to a local symbol. Ie a=b.clone() in Python – Yaroslav Bulatov Nov 23 '23 at 06:13

1 Answers1

1

You can use Copying one symbol into another and store ClearAll-persistent values as DynamicModule variables.

copySymbol // Attributes = {HoldAll}
copySymbol[new_Symbol, old_Symbol] := Language`ExtendedDefinition[new] = 
  Language`ExtendedDefinition[old] /. HoldPattern[old] :> new
x = Range[100];
clean[x_] := Module[{y = 5}, x*5];

DynamicModule[{xLocal = x, cleanLocal} , copySymbol[cleanLocal, clean]

; Manipulate[ ListPlot[cleanLocal[xLocal], PlotLabel -> k] , {k, 1, 5, 1} ] ]

SaveDefinitions is not needed because it saves other than DM's variables and loads them on initialization only. They are still Global` so it will break.

For DynamicModule variables, their values are saved automatically (watch out for SetDelayed OwnValues maybe) and shielded from ClearAll because they end up in FE` context.

But maybe it is worth adjusting your workflow so that Clear["Global`*"] won't affect your Manipulates. A specific solution would require more insight into your work though.

Kuba
  • 136,707
  • 13
  • 279
  • 740
  • Thanks.....is this method robust against restarting Mathematica? Ie, I want my demos to still work when I reopen the notebook? Or is the "copy all relevant code inside manipulate block" the only reasonable way? – Yaroslav Bulatov Nov 23 '23 at 15:34
  • @YaroslavBulatov have you tried, I think it should work. – Kuba Nov 23 '23 at 15:55
  • Yes it works for this example, thanks! BTW why is it that you need to call copySymbol for clean but not for xLocal, is it because of DownValues that don't get copied by DynamicModule? – Yaroslav Bulatov Nov 23 '23 at 17:03
  • @YaroslavBulatov x evaluates to a range so the symbol reference is gone. clean does not evaluate to anything so cleanLocal still references that symbol which may be cleared. – Kuba Nov 23 '23 at 22:02