
Nick wrote (snipped)
The true problem here is that once you got an Event, you never uninstall the callback, even if you just take the first n events and then stop using the stream. This can be really expensive; do you use finalizers to uninstall the callback?
Well there are two approaches: (1) you provide a more complicated function which in addition to the new event, returns an IO () action which unbinds it. This is what HTk does, in general, though for many simple examples it is of course not required. (2) in many but not all cases it is possible to work out that the stream can be automatically deregistered. For example, as well as finalizers you can also forget the stream when the object is destroyed. Of course this isn't anything particular to do with events; a callback model also has to have a way of deinstalling the callback.

On Mon, 10 Mar 2003 18:12:19 +0100
George Russell
Well there are two approaches: (1) you provide a more complicated function which in addition to the new event, returns an IO () action which unbinds it. This is what HTk does, in general, though for many simple examples it is of course not required. (2) in many but not all cases it is possible to work out that the stream can be automatically deregistered. For example, as well as finalizers you can also forget the stream when the object is destroyed.
Exactly the same thing wich I am discussing with A.Reid in haskell-cafe; but finalizers don't "finalize" immediately in some cases, even if they might be satisfying. Moreover, there might be a different approach involving a list of "unsafePerformIO" values to uninstall the callbacks earlier, but I am not sure if it's worth the drawbacks. === AN IMPORTANT NOTE === I want to explain better what you just stated: "a callback model also has to have a way of deinstalling the callback". If we return, together with the stream, the IO action used to unregister the callback, it could easily become of no use if we pass the stream to a new thread. We can't then know when that thread finishes to use the stream (we could pass the closing action together with the stream, anyway), so generally we HAVE to rely on garbage collection and finalizers. But this is the same thing of registering a callback wich multiplexes events to two threads, and the same issue. ===== As usual, if there are two different approaches, each one with advantages and disadvantages, I prefer both, so the interface of a generic Stream library should provide both getStream :: IO [a] and getStreamAndTheOtherThing :: (IO [a],IO ()) The former should use finalizers to deallocate any resource when appropriate, the latter could eventually use them anyway. However, George, there are other problems with streams, wich are leading me to a conclusion; before revealing it :) , here's some sample issue: - sometimes, the stream is produced with a synchronized model: you ask for a stream element only when you are ready to process it. This is used in gtk2 to avoid a backlog of mouse motion messages. We have to find a way (perhaps with a list of unsafeInterleaveIO results) to easily handle such cases; or maybe you already got it ? - if we want a library wich generically models a changing state, we have to deal with three different types, and combination of those: State, Input streams and Output streams. I provide now an example of any of these categories, and of any combination of these (directly taken from the comments I wrote last night on my source code :)) -- The standard input is only an Input, it has no notion of "current" -- value -- The standard output is only an Output -- The current time is only a State, it makes no sense to "listen" to -- it since it's a continuous value, but you can read it at a given -- moment -- An MVar has only State and Output -- A Chan has only Input and Output -- The mouse position has Input and State -- A Port (in M.C. terminology) has Input,Output and State CONCLUSION: I propose here to join our efforts and design a robust and generic stream library, wich has to be thread-safe, and subsume MVars, Channels and M.Chackravarty's Ports. I am doing such a work alone to use it in my future projects, and it grows up well, but of course one thing is me, a student, doing an hobbist work, and another thing is to work together. We don't have to waste time, just to solve the main issues and produce a clean and working implementation. An example of things to decide includes wether to use constructor classes or multiparameter type classes with functional dependencies (once stated that "we are GHC dependent anyway", to quote Axel) My experience (and your, I guess) is that such a library can be implemented correctly in a couple of days, so there shouldn't be any problem, after some week of planning. I propose this just to avoid each stream-lover to rewrite everithing again each time. What do you think? If so, the GUI task force will only have to be kind and use a generic layer for state handling, say a "Var" type with "getVar" and "setVar", so that we can provide an implementation wich also has streams when we are done. If anyone (not just George) is interested, the best thing to do is to post on the haskell mailing list to ask for interested people, and then do the job. What do you think?

On Mon, 10 Mar 2003 21:36:00 +0100, Nick Name
We don't have to waste time, just to solve the main issues and produce a clean and working implementation.
I love this sentence :-)
I propose here to join our efforts and design a robust and generic stream library, wich has to be thread-safe, and subsume MVars, Channels and M.Chackravarty's Ports.
This doesn't sound like a good plan to me --this has a scope way beyond a standard library. It is not clear at all how to do this properly. I do think it is an interesting subject, and I encourage you to pursue your ideas and create a working implementation to show and discuss. Maybe you can even work together with other people to find the right abstractions. Don't get me wrong, I think it is great to discuss these things and it is fun to have this GUI specific list. I just think that certain items shouldn't be part of the common GUI proposal. Let's keep these things seperate. In general, I think that we should only consider items that are a) well understood b) offer (just) enough functionality to implement more ambitious designs Given (b), I would even go for *less* abstraction in order to provide the raw functionalty of the platform -- don't try to protect the user at this level but offer programmers the freedom to create high level designs. All the best, Daan.
On Mon, 10 Mar 2003 18:12:19 +0100 George Russell
wrote: Well there are two approaches: (1) you provide a more complicated function which in addition to the new event, returns an IO () action which unbinds it. This is what HTk does, in general, though for many simple examples it is of course not required. (2) in many but not all cases it is possible to work out that the stream can be automatically deregistered. For example, as well as finalizers you can also forget the stream when the object is destroyed.
Exactly the same thing wich I am discussing with A.Reid in haskell-cafe; but finalizers don't "finalize" immediately in some cases, even if they might be satisfying. Moreover, there might be a different approach involving a list of "unsafePerformIO" values to uninstall the callbacks earlier, but I am not sure if it's worth the drawbacks.
=== AN IMPORTANT NOTE ===
I want to explain better what you just stated: "a callback model also has to have a way of deinstalling the callback".
If we return, together with the stream, the IO action used to unregister the callback, it could easily become of no use if we pass the stream to a new thread. We can't then know when that thread finishes to use the stream (we could pass the closing action together with the stream, anyway), so generally we HAVE to rely on garbage collection and finalizers. But this is the same thing of registering a callback wich multiplexes events to two threads, and the same issue.
=====
As usual, if there are two different approaches, each one with advantages and disadvantages, I prefer both, so the interface of a generic Stream library should provide both
getStream :: IO [a]
and
getStreamAndTheOtherThing :: (IO [a],IO ())
The former should use finalizers to deallocate any resource when appropriate, the latter could eventually use them anyway.
However, George, there are other problems with streams, wich are leading me to a conclusion; before revealing it :) , here's some sample issue:
- sometimes, the stream is produced with a synchronized model: you ask for a stream element only when you are ready to process it. This is used in gtk2 to avoid a backlog of mouse motion messages. We have to find a way (perhaps with a list of unsafeInterleaveIO results) to easily handle such cases; or maybe you already got it ?
- if we want a library wich generically models a changing state, we have to deal with three different types, and combination of those: State, Input streams and Output streams. I provide now an example of any of these categories, and of any combination of these (directly taken from the comments I wrote last night on my source code :)) -- The standard input is only an Input, it has no notion of "current" -- value
-- The standard output is only an Output
-- The current time is only a State, it makes no sense to "listen" to -- it since it's a continuous value, but you can read it at a given -- moment
-- An MVar has only State and Output
-- A Chan has only Input and Output
-- The mouse position has Input and State
-- A Port (in M.C. terminology) has Input,Output and State
CONCLUSION:
I propose here to join our efforts and design a robust and generic stream library, wich has to be thread-safe, and subsume MVars, Channels and M.Chackravarty's Ports. I am doing such a work alone to use it in my future projects, and it grows up well, but of course one thing is me, a student, doing an hobbist work, and another thing is to work together. We don't have to waste time, just to solve the main issues and produce a clean and working implementation.
An example of things to decide includes wether to use constructor classes or multiparameter type classes with functional dependencies (once stated that "we are GHC dependent anyway", to quote Axel)
My experience (and your, I guess) is that such a library can be implemented correctly in a couple of days, so there shouldn't be any problem, after some week of planning. I propose this just to avoid each stream-lover to rewrite everithing again each time. What do you think?
If so, the GUI task force will only have to be kind and use a generic layer for state handling, say a "Var" type with "getVar" and "setVar", so that we can provide an implementation wich also has streams when we are done.
If anyone (not just George) is interested, the best thing to do is to post on the haskell mailing list to ask for interested people, and then do the job. What do you think?
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

On Tue, 11 Mar 2003 00:40:38 +0100
Daan Leijen
I do think it is an interesting subject, and I encourage you to pursue your ideas and create a working implementation to show and discuss. Maybe you can even work together with other people to find the right abstractions.
Oh, yes, my e-mail was meant to G.Russel AND of course anybody else who wants streams. And was meant to take the streams issue outside the GUI list. But, as I said, the GUI team has to leave the road open to a streamed implementation, wich means "abstract over your state". So, in conclusion, I am just looking for people to write this stream library together, not proposing to solve issues here; sorry for not having expressed myself well. Now, if there's someone who cares, I want to give my last contribute to this discussion, or better said monolgue :) Maybe I am wrong, but it seems to me that streams appear something like a research topic to the eyes of some people. I would like to point out that streams are nothing new, and nothing badly understood. The implementation details, and a general framework, are the goals of my proposal, not to study something simple, wich has been there for years. Streams are not a new topic in functional programming. Sometimes they are called "Dialogues". See for example this article http://citeseer.nj.nec.com/jones93imperative.html in wich SPJ and Wadler are *introducing monads*. The previous alternative where streams, indeed. The reason why monads have been introduced is that streams are uncomfortable in many situations, but think about the function "hGetContents" or "readFile", or "getContents". They are just useful in some situations, where you are coding a purely functional algorithm, but need to feed it with non-deterministic input. I repeat: streams are not FRAN, they are nothing new, just a common pattern in lazy functional programming. When a common interface is decided, by G.Russel, me and M.Chackravarty, by the GUI team or by anybody else, I *hope* the "standard haskell GUI library" will have a stream-based interface, since without it the entire program is being compelled in the IO monad, wich is not so easy to code, and not so readable. I hope to have not bothered or annoyed anybody, because I am here to cooperate (for what I can), not to annoy ;-) And, of course, I would have never proposed myself to do a job, if it was not easy to do, and if it was hard to understand from a theoretical point of view. Vincenzo

On Mon, Mar 10, 2003 at 09:36:00PM +0100, Nick Name wrote:
=== AN IMPORTANT NOTE ===
I want to explain better what you just stated: "a callback model also has to have a way of deinstalling the callback".
If we return, together with the stream, the IO action used to unregister the callback, it could easily become of no use if we pass the stream to a new thread. We can't then know when that thread finishes to use the stream (we could pass the closing action together with the stream, anyway), so generally we HAVE to rely on garbage collection and finalizers. But this is the same thing of registering a callback wich multiplexes events to two threads, and the same issue.
==== Yesterday I thought about callbacks like the "expose" event under Gtk. This callback has not only a parameter (which could be handled by a stream) but a return value *and* more constraints: The "expose" callback clears the area to be repainted and marks it as update when the callback returns (this is called "beginPaint" and "endPaint" under Windows). This must be difficult to model with streams or if you spawn threads in a callback. I think abstraction here is more subtle in practice and to develop a universial solution turns out to be more difficult than expected.
Nevertheless, I think streams are nice. Do you think it's possible to define the CGA just with events and implement streams on top of it? If it can be formulated as separate library, then we don't need to solve all these problems right now. Axel.

On Tue, 11 Mar 2003 09:38:23 +0000
Axel Simon
This must be difficult to model with streams or if you spawn threads in a callback. I think abstraction here is more subtle in practice and to develop a universial solution turns out to be more difficult than expected.
Surely ;) I have *never* said streams are good enough for everything. I just don't want to renounce to them in a lazy functional language. The case you are mentioning involves the use of a "Response" type, wich is a mess due to synchronization. In this case a monad (and so, a callback) is just better, and that's why monads are so popular!
Nevertheless, I think streams are nice. Do you think it's possible to define the CGA just with events and implement streams on top of it? If it can be formulated as separate library, then we don't need to solve all these problems right now.
Yeah, that is what I am proposing in the conclusion, I have not really been clear, if you are the second man asking me this: the fact that there are many decisions to take, induces me to say that a general library could be developed outside the GUI task force, if I am not the only one willing to do it; in few words, I changed my mind in response to the discussion, and prefer you and others to concentrate on functionalities and somebody else to solve technical issues about streams. Vincenzo -- Teatri vuoti e inutili potrebbero affollarsi se tu ti proponessi di recitare te [CCCP]

Nick Name wrote: (snip)
I propose here to join our efforts and design a robust and generic stream library, wich has to be thread-safe, and subsume MVars, Channels and M.Chackravarty's Ports. I am doing such a work alone to use it in my future projects, and it grows up well, but of course one thing is me, a student, doing an hobbist work, and another thing is to work together. We don't have to waste time, just to solve the main issues and produce a clean and working implementation.
I think devising something that subsumes everything may be tricky. For example, will this stream library also subsume CML style events (as implemented by me as part of HTk), which allow you to wait on multiple events and return when any one of them occurs? Will it be possible, for example, to "fold" a stream, taking an existing stream and adding a bit of state to it? Will it be possible to block selected elements of a stream? I applaud the idea of devising a general stream library. But I would suggest starting with devising an interface that is extensible as possible, so all such features can be added later on, as necesary.

On Tue, 11 Mar 2003 13:43:32 +0100
George Russell
I think devising something that subsumes everything may be tricky.
Oh, before somebody misunderstoods me badly, and before moving this discussion to an appropriate place, two things: - I would like to subsume just some aspects of things I said. For examples, trying to subsume MVars as a general synchronization structure is far away from the streams, but MVars are also used as shared thread-safe variables, and this is the aspect I wish to model - Of course, I would like a library with necessary types, and not an unique type to subsume them all; this is mainly to avoid things like a read-only variable wich returns "error" on write: there should be a type for readable things and a type for writable things!
For example, will this stream library also subsume CML style events (as implemented by me as part of HTk), which allow you to wait on multiple events and return when any one of them occurs?
Well, this is an example wich requires concurrency. "Merge" of events will be available only on preemptive multithreaded implementation, unless I am wrong and there is an alternative way (like a "select" operator).
Will it be possible, for example, to "fold" a stream, taking an existing stream and adding a bit of state to it? Will it be possible to block selected elements of a stream?
I applaud the idea of devising a general stream library. But I would suggest starting with devising an interface that is extensible as possible, so all such features can be added later on, as necesary.
Yes, and this is way I say "let's work together". You have to point out your issues, everybody else their. We 'll see what stream semantics we are interested in and what are too complex or too rarely used, and decide what's "inside" the library and what's "outside", or else the work could have been done here in the GUI ml. Let's put a deadline, say two months to make the specification of an extensible kernel and to write a correct implementation - if we don't have anything till that deadline, we'll surrender :) Also because I have to ask for my thesis, and after that will not have so much time. Vincenzo

Yes, and this is way I say "let's work together". You have to point out your issues, everybody else their. We 'll see what stream semantics we are interested in and what are too complex or too rarely used, and decide what's "inside" the library and what's "outside", or else the work could have been done here in the GUI ml.
Let's put a deadline, say two months to make the specification of an extensible kernel and to write a correct implementation - if we don't have anything till that deadline, we'll surrender :) Also because I have to ask for my thesis, and after that will not have so much time. Having looked at the Haskell files you sent around some time ago, me
On Tue, Mar 11, 2003 at 04:19:08PM +0100, Nick Name wrote: thinks that such a unified event/syncronization/stream library is too high level for the CGA. In case a) it can be implemented on top of the callback approach then we/you should be able to define a separate library (ok, I said that before) which can be part of a Common GUI Library (i.e. libraries which work with the CGA). In case b), that it has to be interweaved with the API itself, then it will make it hard for high level libraries to use the CGA since they have to match the concurrency model of your approach. I really don't mind having these abstractions, in fact I would try to use them in my applications. But there are so many other approaches that never really caught on which is why we don't want a high-level solution. I know you don't force the user to use your abstractions which contrasts with high-level approaches like Fudgets, Fran, etc, but that should mean that the library can be an addition to the core. About the time scale: How events are modelled is part of the core library (like creation of widgets and layout). Before we do anything else, we have to define this core. Waiting for two months is not too appealing. Sorry to be so negative, Axel.

On Wed, 12 Mar 2003 08:41:19 +0000
Axel Simon
Having looked at the Haskell files
wich are full of errors, I have to do full disclosure even if people is kind :) I wrote 'em quickly to submit here, but I'll do surely better.
you sent around some time ago, me thinks that such a unified event/syncronization/stream library is too high level for the CGA. In case a) it can be implemented on top of the callback approach then we/you should be able to define a separate library (ok, I said that before) which can be part of a Common GUI Library (i.e. libraries which work with the CGA).
I said that too. I am going to implement it as a separate library.
In case b), that it has to be interweaved with the API itself, then it will make it hard for high level libraries to use the CGA since they have to match the concurrency model of your approach.
I don't like forcing people to do something. Streams don't require concurrency, they take advantage of it. An eventual library written by me can separate things that need preemption in a different module.
But there are so many other approaches that never really caught on which is why we don't want a high-level solution.
I repeat for the last time, that streams are not an high-level approach. Please, notice that you, to avoid streams, are USING MONADS! Streams and monads are not really at a different level, IMHO, but they are two different solutions to the same problem, wich is: how to get nondeterminism inside a lazy functional language, and I have noticed, as others, that the ability to mix streams and monads give more expressive power than using just one of them.
I know you don't force the user to use your abstractions which contrasts with high-level approaches like Fudgets, Fran, etc, but that should mean that the library can be an addition to the core.
It will not be in the core, this has already been stated. == Important note: It may be that I don't succeed in doing my work; believe me, it's even probable. It may well be that my work is not well-made, and that you won't be interested in using it. In that case, this does not mean that stream are not useful, or are to be better studied. It just mean *I* am not able to generalize, and in that case, I hope you will take the library of HTk, wich is already well studied, or the Ports library from M.C., adapt it to this standard haskell GUI and make it available as a module in the standard distribution.== I repeat for the last time, lazy lists are one of the fundamental data structures in a lazy language; it's necessary to have them, not because I say so, but because people USE them today. So remember this when you'll be done with the core. Streams are *not* an alternative to Fran. They are just a convenient wrapper over an all monadic program. Just notice the following functions in the base libraries: getContents, hGetContents, readFile, getChanContents, and (newStdGen >>= return . randoms). These are common patterns wich are useful in everyday life of an haskell programmer. I *absolutely* don't want to be polemic, or to impose a personal view. I am just worried about the future of haskell, wich includes a standard GUI. This has to be clear, or I'll seem a troll. Vincenzo -- Scopriti essere umano e in quanto tale persona banale e non speciale a cui Dio concede gesti assai banali. D'ora in poi quello sei tu. [Marlene Kuntz]

On Wed, Mar 12, 2003 at 10:30:39AM +0100, Nick Name wrote:
I said that too. I am going to implement it as a separate library. Ok, ok, ok. SORRY. I probably didn't read the messages carefully enough. No offense but: Why the two month time frame then? If you independently write a library which builds on callbacks, we can add it any time.
So remember this when you'll be done with the core. Please - it's not me. It's more you than me at the moment who shapes the CGA.
I *absolutely* don't want to be polemic, or to impose a personal view. I am just worried about the future of haskell, wich includes a standard GUI. This has to be clear, or I'll seem a troll. Bear with me! Sometimes people (like me) don't understand the first time round or don't read carefully. I try to be more thorough in the future.
Appologies, Axel.

On Wed, 12 Mar 2003 09:41:29 +0000
Axel Simon
Ok, ok, ok. SORRY. I probably didn't read the messages carefully enough. No offense but: Why the two month time frame then? If you independently write a library which builds on callbacks, we can add it any time.
That was a deadline for the whole "generalization project", if someone else was going to participate, and however outside this list; I put that deadline to avoid to infinitely generalize. Like a timeout on a local search, say :) G.Russel is going to give some advice to me, but he is busy right now, and I'll be busy when he is free. No one else is going to cooperate, and I take it as a bad sign, like other stream-experts around are already sure I'll fail; I will try anyway. Vincenzo

Nick Name wrote:
I repeat for the last time, lazy lists are one of the fundamental data structures in a lazy language; it's necessary to have them, not because I say so, but because people USE them today. So remember this when you'll be done with the core. Streams are *not* an alternative to Fran. They are just a convenient wrapper over an all monadic program.
Just notice the following functions in the base libraries: getContents, hGetContents, readFile, getChanContents, and (newStdGen >>= return . randoms).
All of the above except the last one are useless for real-world
programs; primarily because they over-simplify.
Attempting to apply the same approach to a GUI library will fail for
similar reasons, but to an even greater extent.
--
Glynn Clements

On Wed, 12 Mar 2003 14:04:12 +0000
Glynn Clements
All of the above except the last one are useless for real-world programs; primarily because they over-simplify.
I don't think so, but one of the reason I always prefer, when I have to choose, to provide both approaches if possible, is because it avoids religion wars. Since it seems that this philosophy is making me create a religion war, and this makes no sense, I stop it :) Vincenzo
participants (5)
-
Axel Simon
-
Daan Leijen
-
George Russell
-
Glynn Clements
-
Nick Name