[GUI] GUIs and events (was: Re: Concurrency)
Wed, 12 Mar 2003 19:05:51 +0100
George Russell wrote:
> Oh gosh I'm glad we've got a decent debate going on this ...
> Wolfgang Thaller wrote (snipped)
>> 1) Callbacks will be executed synchronously. No other events will be
>> handled until a callback returns.
>> *) This maps directly to the execution model of all backend toolkits
>> that I know
>> *) You can easily get concurrency by calling forkIO, but going the
>> other way is difficult.
> I am strongly opposed to this proposal. As a matter of fact this does
> *not* map directly to the execution model of HTk, in the sense that if
> wanted to add such callbacks to HTk I would have to add an extra lock
> prevent callbacks running synchronously. However there is a more
> fundamental objection.
What do you mean by "callbacks running synchronously"?
Let's assume that, in a button callback, I do some calculation that
takes about one or two seconds, and then show a dialog box. To me,
"asynchronous callbacks" would mean that I could click other buttons
and trigger other actions before the dialog shows. I don't know how to
prevent that if I don't have a guarantee that callbacks are
synchronous. Going the other way is easy - just wrap the callback
handler in a call to forkIO.
> I think in general this does not scale. For example initialisation
> (1) might occasionally need to put up a window (eg one that says
> "Can't find configuration file, please enter new path")
> (2) might, thanks to the common paradigm of doing initialisation using
> unsafePerformIO, need to be run almost anywhere in the program,
> during a callback. The only way of avoiding that is to force the
> to adopt a paradigm where no callback may make use of a service
> might require an initialisation (or anything else) which itself
> a GUI event. This is highly unpleasant.
I think invoking a dialog from unsafePerformIO is highly unpleasant.
But I think you are misunderstanding my proposal.
A callback may, of course, start a "nested" event loop for handling a
modal dialog. You can use all the concurrency you want by wrapping your
handlers in forkIO (if my proposal 2b, or a variant thereof, is
I'll try to rephrase my proposal 1:
1) The event loop will not invoke a callback action until the previous
callback action has returned, i.e. callbacks will be invoked
sequentially, not concurrently.
1a) Event loops may be nested, i.e. a callback, or (if proposal 2 is
also accepted), any other IO action, may call a CGA function that runs
another event loop, e.g. for handling an application-modal dialog (the
main event loop won't handle events during that time).
> Also this way of programming is highly unpleasant. For example, if I
> a button "Send an insult to Simon.Peyton-Jones@microsoft.com" and it
> wants to
> put up a window saying "Do you really want to insult Simon
> Peyton-Jones?" then
> you need a chain of callbacks. The callback attached to the first
> is not allowed to insult Simon PJ itself, instead it has to attach a
> continuation (containing the insult) to the confirmation button. In
> this means continuation-passing-style is going to infect this part of
> program. For programs where almost everything is initiated by user
> an awful lot of them is going to have to be written in CPS.
I think Haskell's type system already makes it illegal to insult Simon
PJ (at least in GHC) ;-).
Seriously, as I said, I was not talking about forcing people to use
CPS. The intent is to allow, but to NOT require concurrency.
In other words, my proposal 1) refers to the same event handling model
as used by GTK, Carbon, and Win32 (with the exception that Win32 uses
an explicit event loop, while the others have RunApplicationEventLoop()
Proposal 2) (especially 2b) talks about extending this to support all
concurrency you could possibly ever want, without forcing concurrency