The register/unregister callbacks issue

Dear all, A lot has been said about the register/unregister of callbacks. In my opinion a programmer should not have to register/unregister callbacks explicitly. The reason for this is that a decent GUI program already is supposed to do proper subsetting of the available callbacks by a number of means. For instance by opening/closing menu (elements), or enabling/disabling mouse, keyboard, window (element)s, menu(elements)... . It is up to the implementation of the platform what the appropriate action is in order to achieve an efficient implementation. On the X Windows platform this seems to be registering/unregistering of callbacks. The MS Windows platform also does not like to keep track of unnecessary mouse movements. A program must explicitly set a flag in order to receive these events. For Object I/O this flag is always set. In addition, a 'filter' function is associated with the keyboard and mouse callback. Suppose mouse events have type MouseState, then the corresponding filter function is of type (MouseState -> Bool). Before the OS sends a mouse event to the callback, it first checks if it passes the filter, and only if so, sends the event. This call is cheap and does not invoke IO actions (unless you use unsafePerformIO). Regards, Peter

Peter Achten
In my opinion a programmer should not have to register/unregister callbacks explicitly.
I don't understand what you're proposing in its place. You say that on X you do need to [un]register callbacks and on Windows you use a filter function to determine whether or not to use the callback. Either way, it seems that there is some mechanism which lets the backend (windows, X, Motif, etc) know that you no longer need to receive events of that type so the API is going to have to provide appropriate functions. That is, there will be a way to register to receive those events and a way to stop receiving those events. Whether they register and unregister a callback or change a bitset defining which events to receive or do something else is largely irrelevant. -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ ps The discussion of the cost of receiving mouse events seems to provide an argument against using streams of events as the base on which other APIs are implemented. If programs explicitly register for events/callbacks, then we can avoid the cost of propagating events that aren't wanted. If the GUI simply spouts a stream of timestamped event objects as in Fran-like systems, then we have to propagate events which aren't needed because there's no easy way to know what events are wanted. (A stream-based system could have operations to turn certain events on and off but this leads to a difficult programming style where you have to coordinate your pure event-stream amnipulation code with your monadic event on/off code.) This isn't to say that streams are a bad model simply that they can't express something that the monadic models can.

Peter Achten
writes: In my opinion a programmer should not have to register/unregister callbacks explicitly.
I don't understand what you're proposing in its place.
You say that on X you do need to [un]register callbacks and on Windows you use a filter function to determine whether or not to use the callback. Either way, it seems that there is some mechanism which lets the backend (windows, X, Motif, etc) know that you no longer need to receive events of that type so the API is going to have to provide appropriate functions. That is, there will be a way to register to receive those events and a way to stop receiving those events. Whether they register and unregister a callback or change a bitset defining which events to receive or do something else is largely irrelevant. What I am saying is that a good GUI program already tells the user (and
At 14:51 19-3-03 +0000, Alistair Reid wrote: therefore also the backend) what events it will respond to. It will disable/enable menu(elements), it will disable/enable window(elements). As a consequence the API has no need for an additional register/unregister mechanism. The filter function is a convenient and light-weight means of additionally telling the backend what kind of events you're (not) interested in in case of enabled gui elements (in particular mouse and keyboard events). Regards, Peter

On Wed, Mar 19, 2003 at 04:40:13PM +0100, Peter Achten wrote:
What I am saying is that a good GUI program already tells the user (and therefore also the backend) what events it will respond to. It will disable/enable menu(elements), it will disable/enable window(elements). As a consequence the API has no need for an additional register/unregister mechanism. What about destroy, add-entry-to-list, repaint, ... events? The programmer must inform the CGA on what events (s)he needs. Ok, a disabled menu item will not trigger callback events but thats an orthogonal issue. IMHO we do need some general concept of callback/event handling. At least its a concept any backend can simulate, even Windows.
Axel.

On Wed, 19 Mar 2003 14:51:31 +0000
Alastair Reid
The discussion of the cost of receiving mouse events seems to provide an argument against using streams of events as the base on which other APIs are implemented.
I think that neither me nor G.R. were proposing this, we wanted to include the feature, among other ones.
(A stream-based system could have operations to turn certain events on and off but this leads to a difficult programming style where you have to coordinate your pure event-stream amnipulation code with your monadic event on/off code.)
Not another e-mail about streams, everybody don't worry; I want to show with a simple example my personal views on the following: 1. how to let different approaches to "time-varying values" cooperate, and how to choose the one wich is appropriate 2. why local state handling must be well designed, and can't be dismissed with an MVar or similar; we could need more features. I might say what is already obvious for other people. In this case, just tell me. I never feel offended by the truth :) [a note, after finishing the post: it took me more than an hour to write this in english... ] SPECIFICATION I want a program that shows a blackboard. Users can press a button to draw onto the blackboard, and another one to stop drawing (perhaps to become able to scroll the blackboard without risking to acidentally modify it). The drawing is persistent on a file and/or synchronized with another instance running elsewere on the net. To draw onto the blackboard, when drawing is enabled, the user keeps the mouse pressed. Once the mouse is released, the curve is interpolated to reduce human errors. Each press of the mouse button starts a new curve. IMPLEMENTATION Now, here's a possible implementation wich could be easy to code, and also lead to readable code, wich is one of the main features of haskell. The major need for implementation is a datastructure wich: - make state changes in mutual exclusion - allows imperative get/set features. - allows state changes to be watched, both with callbacks and streams M.C. Ports libary, whose name I already abused here, does the job. *** 1. The buttons The "draw" button has a callback, which enables the "mouse motion" and the "mouse button 1" callbacks, and writes in a stateful datastructure the IO action needed to unregister them. The "stop drawing" button also has a callback wich unregisters the callbacks. Why do I choose a callback over a stream, to do these actions? It's simple, and I guess that this is the case that people always think about, when they manifest open skepticism to streams in GUIs: the buttons always do the same thing (or quite, it alternates two behaviours); what would I do if I wanted to use a streams of clicks? I would just use a mapM_ over the list, so I ***would be just simulating callbacks***! Why should I do it? Note n. 1: There are TWO buttons. Using ONLY streams would mean to have the streams recurse each other, wich is HARD TO CODE, and HARD TO READ and understand, in my view. *** 2. Drawing the contents on the blackboard on the screen To draw onto the blackboard, I keep a list of curves, built somehow by interpolating the points hit in each draw. This list is in a state variable. I install a callback wich is triggered by state changes, wich draws the entire blackboard onto the screen (of course, optimizations could be done). I choose a callback for the same reason given in (1.) *** 3. Drawing onto the blackboard Of course, here I use streams. I merge (somehow, everybody can imagine how) the mouse position stream and the mouse button stream, and can obtain, with a rather standard function on lists, the list of lists of all the points drawn by the user in each single curve, i.e. the list of all the curve data. Then I map the interpolation function on it and put each curve into the global state. Why do I choose streams over callbacks? Because I am capturing a sequence of evolving states. Doing that in a callbacks means to have a shared list, wich is build from time to time. It's just *** simulating streams ***, why should I do it? I just get another shared variable, wich I hate since I am a functional programmer, and wich makes code LESS READABLE, by decoupling the code from its run over time. In general it appears to me that when you have to capture a time-evolving state in a callback based framework, you *** end up with coding a finite automata, wich sometimes is avoided by using streams. Note n. 2: Activating/deactivating of callbacks is predictable, and can be done elsewhere. It's done in the buttons callbacks. What would be the "purely streamed" approach? To afford the task of unregistering callbacks to finalization, wich means that callback could eventually never be unregistered. This is to show that compromises makes it better. (?!) Note n. 3: The kind of stream used here is one that does NOT get closed when the feeding callback is uninstalled. It just doesn't produce anything. When the callback is reinstalled, it is fed again. Note n. 4: To write state changes onto the stateful variabile of wich at point (2), I will not use event combinators, but I will use a monadic action; this is because in general, as pointed out by SPJ ten years ago, if I did not misunderstand him, using monads over requests/responses is just simpler. Again, I am combining two different approach to gather more expressive power. *** 4. Synchronizing the contents of the blackboard with a file, or a remote blackboard To synchronize the contents, one could use events or callbacks. Issues here are that generally one does not want to save the work more than say, one time per minute. This can be achieved by filtering the event with the right combinator, or by providing the right callback. I don't see advantages in one approach over another. Hope this makes sense to you Vincenzo
participants (4)
-
Alastair Reid
-
Axel Simon
-
Peter Achten
-
Vincenzo Ciancia