
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]. It pretty much did what I wanted, though I made a few changes along the way. Since this seems to be of general use (ie beyond wx), I've proposed to Bastiaan that I package it up for release on hackage, and he's happy for me to do so. Before I do so, I thought I'd ask for comments. The code is on github: http://github.com/gimbo/observer.hs where we have: Control.Observer - a typeclass for observable objects. Control.Observer.Synchronous - an implementation based on IORefs. This is essentially the same as Bastiaan's original, except I've changed the names, split it into two modules, commented it, added one or two small things, and Cabalised it. I've also made a branch where Control.Observer.Synchronous uses MVars instead of IORefs, in an attempt to achieve thread safety: http://github.com/gimbo/observer.hs/blob/threadsafeSync/Control/Observer/Syn... Now, before I make a hackage release: 0. Is this completely insane, in a Haskell setting? Are there better ways to do this that aren't laden with OO-worldview baggage? 1. Does anyone have any comments, on either version? 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? 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? Thanks! -Andy [1] http://www.cs.uu.nl/wiki/bin/view/Afp0607/ExerciseWXHaskell

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.

Hi Neil, On 9 Nov 2009, at 14:50, Neil Brown wrote:
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.
Good point. This occurred to me when I referred to the Gang of Four book, while changing names for consistency. I must confess, in my current project I haven't needed it, but I see your point.
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.
Cool, thanks.
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).
True, but the observers shouldn't be able to access the MVars directly, I think? They should only be able to use the exposed interface, which won't let that happen?
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).
Interesting. That might be quite sensible. My thoughts have probably been coloured by how I've been doing things in wx. Ta for the suggestion. Cheers, -Andy

Andy Gimblett wrote:
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).
True, but the observers shouldn't be able to access the MVars directly, I think? They should only be able to use the exposed interface, which won't let that happen?
Just to clarify -- I meant access to another MVar. Basically, if I do this: do v <- newMVar addObserver sub (putMVar v) If when the observers are run, the MVar v (that I've allocated) is non-empty, my code will block until it is empty, which will also block all the subsequent observers from being run (and block the code that called setValue) until the MVar is cleared by another thread. So my one poorly-written observer could deadlock (or cause stutter in) the system, whereas in the forkIO version, this observer would be fine -- it would block in its own new thread. Thanks, Neil.

On 9 Nov 2009, at 17:41, Neil Brown wrote:
Just to clarify -- I meant access to another MVar. Basically, if I do this:
do v <- newMVar addObserver sub (putMVar v)
If when the observers are run, the MVar v (that I've allocated) is non-empty, my code will block until it is empty, which will also block all the subsequent observers from being run (and block the code that called setValue) until the MVar is cleared by another thread. So my one poorly-written observer could deadlock (or cause stutter in) the system, whereas in the forkIO version, this observer would be fine -- it would block in its own new thread.
Ah yes, of course - I understand. Of course, there's nothing really to stop application authors doing such things in the main thread too... ;-) Thanks for the clarification, -Andy

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...
On Mon, Nov 9, 2009 at 3:50 PM, Neil Brown
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

Andy Gimblett-2 wrote:
To help manage dependencies between state and UI elements, I looked for a Haskell version of the Observer design pattern
Isn't Reactive Programming approach more suitable than Observer if we talk about Haskell? -- View this message in context: http://old.nabble.com/Observer-pattern-in-Haskell--tp26267269p26268135.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On 9 Nov 2009, at 15:21, Eduard Sergeev wrote:
Andy Gimblett-2 wrote:
To help manage dependencies between state and UI elements, I looked for a Haskell version of the Observer design pattern
Isn't Reactive Programming approach more suitable than Observer if we talk about Haskell?
Possibly. Care to expand? If you have a more elegant solution, which fits in well with ordinary wxHaskell, I'd be interested. Cheers, -Andy

Andy Gimblett-2 wrote:
Possibly. Care to expand? If you have a more elegant solution, which fits in well with ordinary wxHaskell, I'd be interested.
I believe there are a few experimental frameworks built on top of wxHaskell which use Functional Reactive Programming, like http://www.haskell.org/haskellwiki/Phooey Phooey . They seem to be more ellegant, but probably less practical for now since they are still experimental. I just thought that FRP is more suitable for Haskell but probably in case of wxHaskell it is not a case. Sorry if it was off topic. -- View this message in context: http://old.nabble.com/Observer-pattern-in-Haskell--tp26267269p26269564.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On 9 Nov 2009, at 16:47, Eduard Sergeev wrote:
Andy Gimblett-2 wrote:
Possibly. Care to expand? If you have a more elegant solution, which fits in well with ordinary wxHaskell, I'd be interested.
I believe there are a few experimental frameworks built on top of wxHaskell which use Functional Reactive Programming, like http://www.haskell.org/haskellwiki/Phooey Phooey . They seem to be more ellegant, but probably less practical for now since they are still experimental. I just thought that FRP is more suitable for Haskell but probably in case of wxHaskell it is not a case. Sorry if it was off topic.
In that case, I am 100% in agreement with you. :-) I do look forward to using such technology in the future... Thanks! -Andy
participants (4)
-
Andy Gimblett
-
Eduard Sergeev
-
Neil Brown
-
Tom Lokhorst