Events in D

bitwise via Digitalmars-d digitalmars-d at puremagic.com
Mon Aug 28 22:10:25 PDT 2017


I needed some C# style events, so I rolled my own. Long story 
short, the result was unsatisfactory.

Library based events are inadequate for basically the same 
reasons as library based properties (often suggested/attempted in 
C++). The problem is that the properties/events don't have access 
to the fields or methods of the containing object, and as such, 
incur the cost of an extra pointer per event/property, or worse, 
a delegate if custom behavior per event is needed, in order to 
provide that access. One obvious example would be synchronized 
properties/events.

Anyways, I threw together some code while thinking about what an 
event may look like in D:

struct Foo
{
     List!(void function()) callbacks;

     @event void onEvent(string op, Args...)(Args args)
     {
         static if(op == "+")
         {
             callbacks.add(args[0]);
         }
         else static if(op == "-")
         {
             callbacks.remove(args[0])
         }
         else static if(op == "()")
         {
             foreach(cb; callbacks)
                 cb(args);
         }
     }

     // or..

     @event {
         void onEvent(string op, Args...)(Args args)
             if(op == "+" && Args.length == 1 && 
isSomeFunction(Args[0]))
         {
             callbacks.add(args[0]);
         }

         void onEvent(string op, Args...)(Args args)
             if(op == "-" && Args.length == 1 && 
isSomeFunction(Args[0]))
         {
             callbacks.remove(args[0]);
         }

         void onEvent(string op, Args...)(Args args)
             if(op == "()" && __traits(compiles, { 
callbacks[0](args); })
         {
             foreach(cb; callbacks)
                 cb(args);
         }

         // this could work in the example above
         // if events just always returned an int
         bool onEvent(string op, Args...)(Args args)
             if(op == "!!" && Args.length == 0)
         {
             return !callbacks.empty;
         }
     }
}

void baz(int n) {
     writeln(n);
}

so usage like this:

`
Foo foo;
foo.onEvent += (int n) => writeln(n);
foo.onEvent += &baz;
foo.onEvent -= &baz;

if(foo.onEvent)
     foo.onEvent(1);
`

becomes this:

`
Foo foo;
foo.onEvent!"+"(() => writeln("bar"));
foo.onEvent!"+"(&baz);
foo.onEvent!"-"(&baz);

if(foo.onEvent!"!!"())
      foo.onEvent!"()"(1);
`

and outputs this:

1



More information about the Digitalmars-d mailing list