Working with DynamicModule: Tracking the progress of Initialization

By default, DynamicModule uses SynchronousInitialization -> True. This causes the initialization to be performed on the preemptive link, disabling any updates to the front-end. In particular, print statements, cell creation and dynamic box updates will all be deferred until the initialization completes.

If we wish to monitor that initialization within the notebook itself, we must turn off synchronous initialization. If we do so, then any of a number of strategies are possible, such as...

... using Monitor to watch x change within a temporary cell:

DynamicModule[{x}
, Dynamic[x]
, SynchronousInitialization -> False
, Initialization :> Monitor[x = 1; Pause@1; x = 2; Pause@1; x = 3, x]
]

... or CellPrint to watch x change within a permanent cell:

DynamicModule[{x}
, Dynamic[x]
, SynchronousInitialization -> False
, Initialization :>
    (CellPrint@Dynamic@x; x = 1; Pause@2; x = 2; Pause@2; x = 3)
]

... or even simply using Print to print out some intermediate information:

DynamicModule[{x}
, Dynamic[x]
, SynchronousInitialization -> False
, Initialization :>
    (x = 1; Print@"1st"; Pause@2; x = 2; Print@"2nd"; Pause@2; x = 3)
]

We can even monitor the initialization of x from within the DynamicModule by overriding the default UpdateInterval -> Infinity on Dynamic:

DynamicModule[{x}
, Dynamic[x, UpdateInterval -> 0]
, SynchronousInitialization -> False
, Initialization :> (x = 1; Pause@1; x = 2; Pause@1; x = 3)
, UnsavedVariables :> {x}
]

It is necessary to add x to the list of UnsavedVariables because without it the value of x will not be seen to change dynamically when the output cell is re-initialized in a new front-end session.

For Debugging Purposes

If debugging messages are our goal, and if it is not acceptable to perform asynchronous initialization for some reason, then a simple solution would be to write logging messages to an external file. That file could then be monitored in real-time using an external utility like tail.

It is possible, if ambitious, to use Mathlink to send debugging messages to a second front-end. See, for example, the chat application in this this question. Personally, I think this is overkill. I would probably spend the time getting the DynamicModule to work with asynchronous initialization instead.


tl;dr;

Use SynchronousInitialization -> False and, in case of simple Dynamic[x], add TrackedSymbols: Dynamic[x, TrackedSymbols :> {x}] due to the bug mentioned below.


Finally I'm able to answer my question with understanding. Two years, no big deal :)

So I want Dynamic[x] to reflect the state of the initialization. The last example in WReach's answer does what I need but in a way I don't like. Dynamic with UpdateInterval->0 is a flood of unnecessary calls. Which will still be performed till that Dynamic is visible.

My understanding and solution to the problem

According to my explanation in:

  • Synchronizing Dynamics with other preemptive evaluations

all we need is to make Initialization code to be evaluated through the MainLink. SynchronousInitialization -> False serves that purpose.

Yet that fix is not working, we still see the initial value and then only the very last at the end.

DynamicModule[{x = 0},
 
 Dynamic[x],
 SynchronousInitialization -> False,
 Initialization :> (
   x = 1; Pause@1;  x = 2; Pause@1;   x = 3
  )
 ]

At this point, a beginner's morale will drop. This should work. Why isn't it? The answer is, come to StackExchange more often. There is a bug which interferes:

  • What is the difference between Dynamic[x] and Dynamic[ h[x] ] for DynamicModule variables?

So my minimal example was too minimal:

DynamicModule[{x = 0},
 
 Dynamic[ x, TrackedSymbols :> {x}], 
 SynchronousInitialization -> False,
 Initialization :> (
   x = 1; Pause@1;
   x = 2; Pause@1;
   x = 3
   )
 ]

Probably the most verbose solution is Dynamic[x, TrackedSymbols :> {x}] which appears to be superfluous but at least it is clear.

Use whatever you want but there is usually something more than x so that bug can be missed.

Uff, works and fits my understanding of Kernel-FrontEnd communication.


Real life example

DynamicModule[{x = 0, init = False},
 Dynamic[
  If[
    init,
    Overlay[{
      Dynamic@ProgressIndicator[Appearance -> "Indeterminate"], 
      Dynamic[x, TrackedSymbols :> {x}]
      }, All, 1, Alignment -> Center,  BaseStyle -> 18
    ],
    x
  ],
  TrackedSymbols :> {init, x}
 ],
 SynchronousInitialization -> False,
 Initialization :> (
   init = True;
   x = 1; Pause@1;
   x = 2; Pause@1;
   x = 3; Pause[1];
   init = False;
   )]

enter image description here