[KBK] writes in comp.lang.tcl (12 February 2001, slightly edited by the author) [[but was KBK responsible for the title [http://www.meyerweb.com/eric/comment/chech.html]?]]: ---- Virtually any [update] is ill-considered! The issue is that [[update]] has virtually unconstrained side effects. Code that calls [[update]] doesn't know what any random event handler might have done to its data while the [[update]] was in progress. This fact is the source of insidious bugs. The problem is pretty pervasive, once an application reaches a certain level of complexity. One example that I had was: * Messages arrive on sockets from various places. Certain messages describe urgent conditions that caused a dialog to be posted. The code that positions the dialog on the screen uses [[update]]. * Messages arriving on the sockets also allow for urgent conditions to be dismissed (say, because a piece of equipment starts responding again). Now consider the following sequence of events. * A sender detects an urgent condition, and then immediately detects its resolution. The two messages (creating and dismissing the dialog) wind up back-to-back on a socket. * The 'readable' handler for the socket is entered, and reads the first message. As part of processing the message, a dialog is posted, and the code that posts it enters [[update]]. * The event loop is now free to process events, and re-enters the 'readable' handler for the socket. Now the message that dismisses the dialog gets processed and destroys the window. * The [[update]] eventually returns and tries to do the [[winfo width]] and [[winfo height]] to begin its geometry calculation. But the window no longer exists -- step 3 destroyed it -- and so the geometry calculation throws an error. Mind you, this is an ''easy'' example. Imagine trying to track down the problem if you have custom C code making callbacks with ''Tcl_Eval'' and its friends. One of the callback scripts does an [[update]], and the event handler winds up deleting or making radical modifications to data structures being maintained in the C code. On return from the [[update]], you get a pointer smash with absolutely nothing to go on. Yes, you can avoid these problems. You can play games with the event loop (unbinding events that could cause trouble). You can re-check the world after an [[update]]. You can twiddle bits in the event mask. You can do smart things with ''Tcl_Preserve''. You can have your file-events trigger idle callbacks so that you know that all data have been collected from the socket before the callbacks fire. (And then you get the shaft from an unexpected [update idletasks]!) I have better things to do with my time! It's usually much cleaner and easier to debug if you structure the code with chains of [event] bindings. For instance, you can use a [bind]ing to trigger positioning a window (as in [Centering a window]). If you do, there's no [[update]] confusing things; the process simply returns to the event loop. If a subsequent event deletes the window before it is configured, no problem, the binding goes away and the handler never fires. You can think of the window as a state machine, and each event as a state transition. The use of [[update]] to [Keep a GUI alive during a long calculation] can also be avoided (a simpler development of the principle appears in [Countdown program]). Moreover, except for the very simplest applications, the resulting code is cleaner and easier to integrate and maintain (although slightly more verbose). I'd go as far as to say that I've never seen code where [[update]], a single-argument [[[after]]], [[[vwait]]] or [[[tkwait]]] is really needed, except for a [[vwait]] that initially launches the event loop. And I've seen lots of timing issues like the one I described above. Personally, were it not for the code it would break [[[AMG] adds: ''the code is broken to begin with'']], I wouldn't cry if [[update]] were removed from the language altogether. [NEM] 2010-07-28: I would add some notes to this. Firstly, it is not always obvious that you are calling one of these difficult commands. For example, [tk_messageBox] calls [vwait] as part of its workings. I have been caught by this before, in a similar manner to [KBK] (popping up dialog boxes in response to socket messages), and it can be hellish to debug. Secondly, be aware that [coroutine]s can also lead to these kinds of problems if not controlled: a [yield] to the event loop is equivalent to a non-nesting [vwait]. Concurrency is a cruel mistress. <> Discussion | Concurrency Concepts