Assume you have two stream panes in a single-thread CLIM implementation (that is *multiprocessing-p* -> nil). By some means you trigger stream-read-char on the first pane. As there is no character available stream-read-char will block and start a subsequent event processing loop, checking if there is a character arriving on its pane. But there won't come any character. In the meanwhile the event processing loop running inside of stream-read-char causes via some other handle-event that a second stream-read-char is started. Again causing an event loop.
Problem #1: The event loop of the second stream-read-char does not know anything about the loop condition of the first event loop.
Problem #2: Problem #1 can be curred by making some "global" state of event conditions. However, It can't do anything about even if it would know when the first stream-read is supposed to terminate. Because to return to the first event loop, it would have to stop blocking, but it's not allowed to do that. There is no way stream 1 can process its character before stream 2 got its (and further assuming that the code calling stream-read-char exits).
Conclusion: CLIM can not be implemented on a single-thread system as it is specified.
Continuations a solution? Rather not. event-read would to be specified as a macro that takes a body argument used in a closure. For instance,
(event-read (event sheet) (process-event event))
But there is nothing like that in the CLIM spec. So we either support stream reading cleanly or we forbid synchronous event processing at all. We can't have both. Not with this CLIM spec.
(Remark: UCW got it right. A former version of UCW uses continuations to fix the problem of "proper problem encoding". Our brain does not think in terms of events. We don't envision problem solutions in terms of state machines. We envison solutions as linear flow. See: http://common-lisp.net/project/ucw/docs/html/rest/rest.html - An interesting thing about UCW is also that it doesn't require deep nesting of sexps as it uses (actually has used) a code walker to transform code into CPS. It can be found here http://common-lisp.net/project/bese/docs/arnesi/html/Automatically_Convertin... )
I actually wanted to write about the fact that McCLIM does not have per-pane event queues. But before I can have a look at this topic, I rather discuss how CLIM events should be handled at all. If we are actually going to change something in this area, I would also like to define:
Who is allowed to read an event and when? What are the priorities if there are more than one event consumers? How is event consumption of event-read related to handle-event; Is handle-event the default event-processing mechanism by the default event-reader, so that handle-event is a fallback if there are no other event-readers (than the default)?
See stream-read-char, stream-read-char-no-hang, handle-non-stream-event in stream-input.lisp, standalone-event-loop in panes.lisp, simple-event-loop in frames.lisp for more.
Isn't the lesson here to not read from streams inside event handlers? I don't understand why one would do this.
Andy Hefner ahefner@gmail.com wrote:
Isn't the lesson here to not read from streams inside event handlers?
In a single-thread system, it does make any difference if it's an event handler or command or something else.
And if you think stream-read are too low level anyway, simply think of two accepting-values forms. The second will instantly cause trouble for the first.