# How to write crash-robust code?

When a notebook crashes all the work I was doing is lost - I'd like to ameliorate this situation!

Is there a way to decorate a symbol so that it is saved to disk whenever it changes, or after a certain repeating time interval?

I find myself wasting lots of time manually performing such a disk-caching mechanisms for important variables and functions (usually by appending to global lists and saving new .mx files with DumpSave by hand). Here's what I'd like to call it:

CrashProtect[_Symbol] := (* ... *)
CrashProtect[_Function] := (* ... *)


I realize there is overhead involved but typically only a few symbols or functions are critical and would need this sort of treatment.

Note: MMA 10.3 kernel is more stable than ever! Sadly the front-end crashes for me still very frequently - especially when dealing with dynamics or large/multiple notebooks.

• You have Mma 10.3? – Szabolcs Aug 21 '15 at 19:40
• \$Post comes to mind. – Sjoerd C. de Vries Aug 21 '15 at 20:30
• Related, see especially the "File-backed In-memory Approach" section. – Alexey Popkov Aug 21 '15 at 21:26
• You might want to check out LocalSymbol and LocalObject. – Stefan R Aug 21 '15 at 22:15
• Also PersistentValue, if you have 11.2. Allows you to save persistently in a Notebook. – b3m2a1 Jan 2 '18 at 16:31

### If you can keep a cell on screen, Dynamic can do it.

Perhaps not the prettiest of methods, but here's one possible approach:

autobackup[x_, f_] := Dynamic[Put[x, f]; "Magic cell - used for backup.",
UpdateInterval -> 30, Initialization :> (x = Get[f];)];


Takes a variable x and file path f, and creates a Dynamic cell that automatically saves the value of x to disk at f whenever x changes (specifically, when those changes trigger Dynamic cells) or every 30 seconds. It then reloads those values from the disk whenever the Dynamic cells are initialized, providing continuity across kernel sessions.

Will not work with functions specified in the standard SetDelayed (:=) syntax, but should work with functions specified as f=Function[{x},x+...], which may be useful in some projects.

This does require keeping the magic cell around though, since that's what the Dynamic is attached to, and thus the output should not be suppressed with ;.

Reloading the values after a kernel crash/quit may require re-running the autoupdate input cells.

### Otherwise, you can schedule a repeating task to save at a constant time interval.

autobackup[x_, f_, t_] := (If[FileExistsQ[f], x = Get[f]];
SetAttributes[autobackup, HoldFirst];


This takes a variable x, file path f, and time between saves t, and creates a scheduled task which will attempt to save x to f every t seconds.

### If you want dynamic updating without the magic cells, you can attach the Dynamic to the notebook.

autobackup[xl_List, f_] :=
SetOptions[EvaluationNotebook[], NotebookDynamicExpression ->
Dynamic[
If[nbdeinit === True, Put[Evaluate[xl], f],
If[FileExistsQ[f], xl = Get[f]];
nbdeinit = True],
TrackedSymbols :> xl]];
SetAttributes[autobackup, HoldFirst];


This takes a list of variables xl and a file name f, and sets up a NotebookDynamicExpression which will update so long as the notebook is open. This does require the use of a dummy initalization variable, because apparently the Initialization rule for Dynamic won't trigger for NotebookDynamicExpression. Also note that this doesn't appear to recover gracefully from kernel crashes unless the notebook is reopened, though it won't break anything either (the Dynamic is simply not evaluated at all, it seems).

• This will work only while the Dynamic cell is displayed on the screen... – Alexey Popkov Jan 2 '18 at 7:11
• Is that so? That can be somewhat mitigated by having it in a separate notebook on another screen, rendered; but that becomes very convoluted quickly. I'll take a look at alternatives. – eyorble Jan 2 '18 at 7:12