Standard Event Driven Object Library for D
Christopher Wright
dhasenan at gmail.com
Tue Apr 1 07:45:52 PDT 2008
Brian White wrote:
> What do others think of this?
>
> -- Brian
% toc:
% events
% events in stdlib
\section{events}
I'm also interested in the subject, though I haven't had a chance to
work on it. (I'm trying to get a full agile setup in D; I've done mock
objects, an xUnit, and dependency injection system so far. Events are on
my list, but not yet accomplished.) What sort of API would you want?
Jeremy Miller's event system (in C#) looks like:
interface IListener<T>
{
void Handle(T subject);
}
class EventPublisher
{
public void AddListener(object o){}
public void Raise<T>(T subject){}
}
That does a simple O(n) loop on each event to see if any of the
registered objects can be converted to an IListener<T>. This is
convenient because any class can listen to an arbitrary number of
events. It is inconvenient that publishing an event is linear in the
number of total listeners rather than the number of listeners for that
event. You probably could do some reflection to find which events an
object listens to, though. (I wouldn't particularly want to do that in
D1, though.) Also, you can't use structs to receive events, if you
translate it to D.
The other issue is that you need to create a class (or probably struct)
for every event you use.
CAB and Ayende Rahien's event broker both use strings to describe which
event you care about. This means you have fewer UDTs, but then you're
using strings, which have zero validation. It also makes it a bit more
ugly to provide arguments. Jeremy Miller's system has the best
validation -- it's your code that won't compile if you don't listen to
the event properly. The worst you could do is send the wrong event and
have the wrong stuff happen rather than send an event and have nothing
happen -- the former is probably a bit easier to debug. Using strings as
event URIs has a benefit that you can use hashing. However, it requires
more configuration.
Events are easier to work with if you use hooks into a dependency
injection tool to wire them up. There is, at last count, exactly one
dependency injection library for D, and that's mine. Dconstructor
doesn't currently support interceptors that run after the construction
of an object. But for event listeners, you could still put a line in the
constructor:
// if you're using dependency injection
this (EventRegistrar events)
{
events ~= this;
}
// if you're using the singleton pattern
this ()
{
EventRegistrar.instance() ~= this;
}
\section{events in stdlib}
I'm not sure that sockets with events are appropriate for the standard
library. You'd need, at a minimum, one extra thread that the sockets
operate on, unless you still had a socket set that you polled. This
means that any application that used a socket would need to concern
itself with thread safety.
This would be okay if you had two classes for sockets in the stdlib, say
PollingSocket and EventSocket. But still, I would want to control my
threads. You could instead have a static method on EventSocket that
polls each EventSocket (or uses a SocketSet to do so), and if any socket
that has something to report, it will publish the appropriate event.
Still, I'm not sure something like this belongs in the standard library
quite yet.
More information about the Digitalmars-d
mailing list