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

Dmitry Olshansky dmitry.olsh at gmail.com
Wed Jul 7 07:08:57 PDT 2010


On 07.07.2010 14:54, Jacob Carlborg wrote:
> On 2010-07-07 10.48, Dmitry Olshansky wrote:
>> 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.
>
> I think it would be nice to simulate the events in C#. It's quite 
> easy, just a struct containing a linked list of delegates, a function 
> to call all the delegates and functions to add and remove delegates 
> from the list.
>
Never actually used C#, but I'm doing something alike, just with built 
in array instead of list, given the fact that number of callbacks is 
usually well under 100, it's should be faster and waste less space. I'll 
upload my efforts on dsource, when it's finally usable.

-- 
Dmitry Olshansky



More information about the Digitalmars-d-learn mailing list