std.pattern.. templated publisher subscriber pattern, adding events to collections

Dmitry Olshansky dmitry.olsh at gmail.com
Wed Jul 7 01:48:59 PDT 2010


On 07.07.2010 2:47, BLS wrote:
> Okay a  bit better snippet than before. snippet should be almost 
> functional..
>
> /*
> Hi,
> Andrei brings in the idea of std.pattern. Seems that this module is
> "stalled";  Unfortunately !
> However I would like to enhance collection classes (likewise
> dcollections)  with a Publisher - Subscriber pattern (signal - slot, or
> observer pattern) , if you prefer)
> Hope the idea of enhancing collections with events become clear with the
> following snippet.
> !!! I am able to spend just a few hours a month with D programming.. in
> other words, please don't kill me :)
> Untested Draft code which requires a lot of help and ,more important,
> feedback from you.
>
> */
>
> struct publisherMsg(T) {
>     T data;
>     Action a;
> }
>
> mixin template Publisher(T) {
> private :
>
>     enum Action = {INSERT, UPDATE, DELETE, READONLY};
>     //alias typeof(this) PT;
>
>     struct receiver {
>         Object o;
>         callback cb;
>     }
>
>     receiver[] subscriber;
>
>     publisherMsg!(T) msg;
>
>     alias void delegate(const ref msg) callback;
>
>     void addSubscriber(object o, callback cb) {
>         //subscriber ~= o;
>     }
>
>     void publish() {
Now where are arguments? kind of  (T t,Action act)
>         foreach  (object o ; subscriber)
>         {
>         // create message and send message
>
>         }
>     }
The considerations are still the same :
     foreach(c;subscriber)
         c.callback(
  see my erlier post
> }
>

> mixin template Subscriber() {
>   // see UndoList for implementation
> }
>
> final class Stack(T, bool observable = false ) {
>     T[] data;
>
>     static if (observable)    mixin Observable!T;
Yes, I think Observable is more appropriate then Publisher. Then maybe 
methods should be:
addObserver instead of addSubscriber,
notify instead of publish?
But back to the whole idea - I'm sure you do not want to reimplement all 
the shiny std.container.
What I think we basically need is universal wrapper for _any_ container 
stuff.
let's call that Observable!Cont. Something like :
final class Observable(Cont){
     Cont cont;
     //here goes your current Publisher stuff
     //...
     alias Cont!ElementType T;
     static if(__traits(compiles,cont.insert(T.init)))//some such ... 
need to test if it has this method
     {
        size_t insert(Stuff)(Stuff s){//trouble is - we could insert 
anything that converts to T
             size_t n = cont.insert(s);
             notify(cast!(T)s,Action.Insert);
         }
     }
    //and all such stuff from std.continer.TotalContainer
     //in theory could even be generated from phobos source
     ....
}
usage :
    alias Observable!(Array!int) observableArray;
     observableArray arr = [ 4,5,6]; //that would be nice
     arr.addObserver( (ref msg m){ writeln("arr insertion: 
",to!string(m.data,m.action));
     arr.insert(42); //should print that fancy message
     ...
Yes, I still think that plain delegates approach is more flexible and 
straightforward (see my earlier post).
>
>     void push( T t) {
>         data ~= t;
>         publish(t, Action.INSERT);
>     }
>     T pop() {
>         publish(t, Action.DELETE);
>         //...
>     }
>     bool empty() {
>
>     }
>     T top() {
>         publish(t, Action.READONLY);
>         //...
>     }
>     size_t size() {
>
>     }
> }
> // Undo list will receive every pushed or popped item -data and action)
> class UndoList(T) {
>     private:
>     T[] data;
>
>     /// should be part of the sunscriber mixin templates.
>     publisherMsg!T stackMessage;
>
>     void delegate(const ref stackMessage) dg;
>
>     alias Stack!(int) IntegerStack;
>
>     IntegerStack intstack = new IntegerStack;
>
>     private this() {
>         dg = &this.feedback;
>
>         // SUBBSCRIBE Stack(T) push and pop events.
>         intstack.addSubscriber(this, dg);
Again from my POV it could be:
     intstack.addSubcriber(
         (const ref stackMessage msg){ feedback(msg); }
     );
//somewhat scary in this case, but in fact it does not restrict you to 
class instances.
>
>     }
>     public void feedback(const ref stackMessage msg ) {
>         writefln("Action");
>     }
> }
BTW I'm definitely interesed in this effort, and in fact want that kind 
of functionality for my upcoming gui lib.
It all just needs to be more reusable and flexible.

-- 
Dmitry Olshansky



More information about the Digitalmars-d-learn mailing list