At times I'll find myself building a some interface component where I want to have some localized dynamic variables, and while testing I might realize that some bit of the code needs to change, which means I lose the current state of all the localized variables, some which might be bothersome to set once again. In such case my typical solution is something like:

  persistant = 21,
  transient = 2},
  Deinitialization :> (saveVar = persistant),
  Initialization :> (FinishDynamic[]; If[ValueQ[saveVar], persistant = saveVar])

Which will retain the value of persistant even if I rerun the code. However if you have a bunch of variables that you want to retain it becomes bothersome to save each and everyoen and reload them, and what more you might want to save DownValues as well as OwnValues so I thought that I'd make a bit more general solution using DumpSave or Save to save definitions and load them in using Get:

Deinitialization :> (If[FileExistsQ["tempfile"], DeleteFile["tempfile"]];
       Save["tempfile", {persistant}]),
Initialization :> (FinishDynamic[]; If[FileExistsQ["tempfile"], get["tempfile"]])

But when trying this I've run into problems since the names that are saved are the local temporary names eg. FEpersistant$$161instead of justpersistant` which means the values aren't loaded back again correctly. So my question is whether theres either another way to achieve a similar result or if the naming problem can be resolved


This can be done by reading the saved symbol and copying it to the new one

Below I define copySymbol that copies the definition of a symbol to another and making sure that the FE context is not excluded.

saveSymbol Saves a given symbol in $TemporaryDirectory, for instance FE'abc$123 is saved as MMAsave_abc_FE'abc$123 (read ' as `)

readSymbol takes a name and a destination symbol, and Gets the corresponding definition and copies it to the destination symbol, with some trickery to avoid evaluation of OwnValues along the way. By looking at the last part of the filename it knows which symbol to copy.

removeSymbol takes a name as argument and removes everything in $TemporaryDirectory that begins with "MMAsave_"<>name<>"_" to help remove all old definitions.

ClearAll[copySymbol, saveSymbol, readSymbol];
Attributes[copySymbol] = HoldAll;
copySymbol[old_ /; Head[old] =!= Hold, new_] := (
  Language`ExtendedFullDefinition[new] = 
   Language`ExtendedFullDefinition[old, "ExcludedContexts" -> 
       OptionValue[Language`ExtendedFullDefinition, "ExcludedContexts"],
       "FE"]] /. HoldPattern[old] :> new)

Attributes[saveSymbol] = {HoldFirst};
SavePrefix = FileNameJoin@{$TemporaryDirectory, "MMAsave_"};
saveSymbol[sym_] := With[
  {name = StringReplace[SymbolName[Unevaluated[sym]], 
     name_ ~~ "$" ~~ ___ :> name]},
  Save[SavePrefix <> name <> "_" <> Context[sym] <> 
       SymbolName[Unevaluated[sym]], sym]]

Attributes[readSymbol] = {HoldAll};
readSymbol[name_String, dest_Symbol] := Block[{
   file = First@FileNames[SavePrefix <> name <> "_*"],symname},
  symname = StringReplace[file, 
    SavePrefix ~~ name ~~ "_" ~~ symname_ :> symname];
  With[{old = ToExpression[symname, InputForm, Hold]},
   copySymbol[old, dest] /. 
    HoldPattern[copySymbol[Hold[a_], b_]] :> copySymbol[a, b]

removeSymbol[name_String] := DeleteFile@FileNames[SavePrefix <> name <> "_*"];
savedSymbolQ[name_] := Length[FileNames[SavePrefix <> name <> "_*"]] != 0

It can be used as follows:

DynamicModule[{persistent = 21, transient = 2}, 
   InputField[Dynamic[transient]], Dynamic[persistent*transient]}],
 Deinitialization :> (removeSymbol["persistent"]; saveSymbol[persistent]), 
 Initialization :> (FinishDynamic[]; 
   If[savedSymbolQ["persistent"], readSymbol["persistent", persistent]])]
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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