I haven't looked at the code extensively, I just wanted to comment on this point:
> There is no way to remove an observer, which is something I'd expect to have > available. I realise this would require assigning a key to each observer > (and thus perhaps storing them in an associative map) or some way to filter > them, but I think if you can only ever add observers, it will get awkward. It might be convenient to have the `addObserver` function return a "detachment function" as its result. At Microsoft, Erik Meijer is working on an "Rx framework" [1], which is an implementation of the GoF Observer pattern. The implementation is, as Erik describes it, the mathematical dual of the Enumerable pattern. In the Rx framework, the `addObserver` method returns an `IDisposable` object with a single method `dispose()`, this will detach the observer from its subject. This is more convenient than trying to remember the unique object identity of the observer (as that disallows anonymous lambdas). I don't know how this would work in a Haskell context, but it might be interesting to think about. - Tom Lokhorst [1]: http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/ On Mon, Nov 9, 2009 at 3:50 PM, Neil Brown <nc...@kent.ac.uk> wrote: > Andy Gimblett wrote: >> >> Hi all, >> >> I've been doing some GUI programming recently, using wx. To help manage >> dependencies between state and UI elements, I looked for a Haskell version >> of the Observer design pattern, and I found an implementation written by >> Bastiaan Heeren of ou.nl [1]. >> >> Now, before I make a hackage release: >> >> 1. Does anyone have any comments, on either version? > > There is no way to remove an observer, which is something I'd expect to have > available. I realise this would require assigning a key to each observer > (and thus perhaps storing them in an associative map) or some way to filter > them, but I think if you can only ever add observers, it will get awkward. > >> 2. In particular, is the MVar version sensible? I'm aiming for mutual >> exclusion between threads. I _think_ I've got it, but I'm perhaps not >> familiar enough with the semantics of MVar to be certain. Advice >> appreciated. If it _is_ sensible, then is there any reason not to just use >> this, and discard the IORef version? > > It looks fine (and thread-safe) to me, but I'd agree that you may as well > just use the MVar version and leave out the IORef version. > >> The current implementation is synchronous, in that any observer functions >> are called immediately and synchronously (and in the same thread as the >> change of subject value). I'm pondering extending the package with an >> asynchronous version where the update just trips a flag, and the observer >> function picks this up later - possibly in another thread. The idea there >> is to help in cases where certain operations have to be in a particular >> thread. But this will mean a change to the typeclass too, I guess - or the >> addition of another one for observers themselves. Again, any thoughts? > > I was a bit surprised at first that the observers were called synchronously. > Asynchronous is what I'd expect, and it's also harder to code the > asynchronous handlers wrongly. One blocking call (such as putMVar) in a > synchronous handler can screw up your whole program by delaying the > subsequent observers (and at that stage, the order in which the observers > were added begins to matter). But my idea of how asynchronous would be > implemented seems different to yours, judging by your description. Why not > just augment this function in the synchronous version: > > notifyObservers :: Subject sub val => sub -> IO () > notifyObservers subject = > do value <- getValue subject > observers <- getObservers subject > mapM_ ($ value) observers to become: > > notifyObserversAsync :: Subject sub val => sub -> IO () > notifyObserversAsync subject = > do value <- getValue subject > observers <- getObservers subject > mapM_ (forkIO . ($ value)) observers > > This is what I was expecting to happen -- all the observer actions are > spawned off into their own thread to run whatever code they want (either > communicating back to an existing thread, or performing some long in-depth > action). > > Thanks, > > Neil. > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe