[phobos] Improving std.signals

Johannes Pfau johannespfau at googlemail.com
Wed Sep 29 07:16:32 PDT 2010


 Hi,
I needed signals for a simple test program some time ago and because I
wanted to learn D templates anyway I coded my own signal implementation.
I then saw phobos already had an implementation of signals and slot in
std.signals, but I was kinda disappointed by the implementation in
std.signals. D offers the possibilities to enhance it in many ways.

The limitations of std.signals:
*Only supports delegates, not even functions. And it should also support
objects/structs with opCall
*Only supports delegates of class objects.
The std.signal implementation attaches a DisposeEvent to the object of
the delegate. This only works for classes. It first sounds like a good
idea to automatically remove the delegate when the object is destroyed,
but: explicit delete is deprecated; the garbage collector should not
collect the object while the delegate is still registered; it limits
delegate support to class delegates; requiring the user to explicitly
remove the delegate is ok. Most(all?) signal implementations require
explicitly removing the signal handlers.
*Delegates return void. Most signal implementations have handlers return
bool. When a handler returns false, the remaining handlers are not called.
*Uses template mixins. Template structs work as well and give a nicer
syntax.

So I merged my signals implementation with std.signals. All problems
mentioned above have been fixed. I additionally added the following things:
*Support all handlers with void or bool return type. Using bool return
type is preferred though, because it's faster.
*Overloads for += and -= like in C#

I also came up with a pretty nice use case for structs with opCall:
Consider this common c# code:
public delegate void ChangedEventHandler(object sender, EventArgs e);
The sender object is part of the Signal type. Now, this won't work for
D, because structs aren't objects and signals can be at module level as
well.
But the struct + opcall support allows us to do this in a even better way:
struct Handler
{
    object _sender;
    bool opCall(string s)
    {
         //use _sender and s
    }
    this(object sender)
    {
        this._sender = sender;
    }
}
obj.onDatareceived.connect(new Handler(obj));

Using this technique we can pass any number of additional arguments.
This could also be used to build an signal->message passing dispatcher:
obj.onDatareceived.connect(new EventMessage!string(tid));

I then looked into the glib api documentation to see what additional
functionality it's signal handling offers.
It's basically:
 * Handler IDs.
this would allow us to add the same handler to a signal multiple times.
It also makes addafter/before easier, but it's not required for that.
I wonder whether phobos already has something like an IDPool, something
like this: http://ideone.com/xs80c
 * block/unblock complete signal (easy to do)
 * block/unblock handlers (shouldn't be too hard)
 * threading? (Is this useful/ needed?)
 * addafter / before (Adding handlers before a specific handler)
 * is handler connected? (easy)
 * stop signal emission (only useful when used with threading)

If the new code was accepted into phobos, I'd offer to implement the
features above as well, if desired.

The proposed new std.signals code is located here:
http://ideone.com/NHS5C

-- 
Johannes Pfau



More information about the phobos mailing list