Suggestion: signal/slot mechanism

Lutger lutger.blijdestijn at gmail.com
Tue Sep 5 17:50:02 PDT 2006


Kristian wrote:
<snip>
> Bruno Medeiros wrote:
> 
>> I see, so a S/S object also knows which signals point to his slots. 
>> Still, a base class is not required, a mixin can do the job nearly as 
>> well.
>>
>>> I think everybody will agree if I say that the optimal solution would 
>>> be D supporting S/S mechanism directly.
>>>
>>
>> I disagree. If D can support S/S without additional languages 
>> constructs, and with nearly the same easy of use as Qt's, then that's 
>> enough.
> 
> 
> Well, I think the key sentence here is "almost as easy as". Will it be 
> easy enough for the majority?
> 
> The S/S mechanism is a very simple structure. If you build it 'right', 
> then there is no room for competition (because you cannot make it 
> simplier). And being simple, it won't bloat the language. Instead it'll 
> extend the language 'naturally'.
> 
> Mixins and templates would make the mechanism quite complex. That would 
> bloat the *code*.

Of course you are right that built-in S/S can be cleaner (and more 
efficient), IIRC C#'s events are something like it. But it also has some 
disadvantages, for example boost::signals is quite different than QT's, 
and the latter also has features for introspection. These libraries (as 
a whole) are higher-level than is reasonable for D to incorporate into 
the language.

I'm also not saying that dcouple is poorly written, but I think it can 
be done a little clearer. This thread inspired me to work on the managed 
part of my sigslot module, below I've added how your example looks like 
in it. It also handles other callable types (like free functions). There 
is no need to derive from any class or interface.

class Foo {
     void setValue(int value) {
         ...
         valueChanged1();
         valueChanged2(oldVal, value);
     }

     Signal!() valueChanged1;
     Signal!(void, int, int) valueChanged2;
}

class Bar {
     this() {
         foo = new Foo;
         foo.valueChanged1.connect(handleFoo(), this);

         foo2 = new Foo;
         foo2.valueChanged2.connect(handleFoo(), this);
     }

     void handleFoo() {...}
     void handleFoo(int oldValue, int newValue) {...}

     Foo foo, foo2;

     mixin SlotObjectDestructor;
}

> For example:
> 
> /* ----- Qt-styled way with some modifications */
> 
> class Foo {
>     void setValue(int value) {
>         ...
>         emit valueChanged();
>         emit valueChanged(oldVal, value);
>     }
> 
>     signal valueChanged();
>     signal valueChanged(int oldValue, int newValue);
> }
> 
> class Bar {
>     this() {
>         foo = new Foo;
>         connect foo.ValueChanged() to handleFoo();
> 
>         foo2 = new Foo;
>         connect foo2.valueChanged(int, int) to handleFoo(int, int);
>     }
> 
>     void handleFoo() {...}
>     void handleFoo(int oldValue, int newValue) {...}
> 
>     Foo foo, foo2;
> }
> 
> 
> /* ----- dcouple-styled way */
> 
> // The Widget class implements the S/S handling.
> // It's derived from dcouple's SignalSlotManager.
> // Its implementation is omited here.
> 
> class Foo : Widget {
>     this() {
>         sigValueChanged1 = new Signal!()(this);
>         sigValueChanged2 = new Signal!(int, int)(this);
>     }
> 
>     void setValue(int value) {
>         ...
>         sigValueChanged1.emit();
>         sigValueChanged2.emit(oldVal, value);
>     }
> 
>     Signal!() sigValueChanged1;
>     Signal!(int, int) sigValueChanged2;
> }
> 
> class Bar : Widget {
>     this() {
>         foo = new Foo;
>         slotHandleFoo1 = new Slot!()(this, &handleFoo1);
>         connect(foo.sigValueChanged1, slotHandleFoo1);
> 
>         foo2 = new Foo;
>         slotHandleFoo2 = new Slot!(int, int)(this, &handleFoo2);
>         connect(foo2.sigValueChanged2, slotHandleFoo2);
>     }
> 
>     void handleFoo1() {...}
>     void handleFoo2(int oldValue, int newValue) {...}
> 
>     Slot!() slotHandleFoo1;
>     Slot!(int, int) slotHandleFoo2;
> 
>     Foo foo, foo2;
> }
> 
> I am not saying that dcouple is poorly written or anything (far from 
> it!), but the benefits of the direct support is obvious IMHO:
> 
> - Less code (and less potential bugs).
> - Clearer syntax which is easier to read/write.
> - Signals can be connected to any object and function.
> - No need to use a base class (or mixins).
> - Function overloads can be used.
> - Guaranteed to be bug free.



More information about the Digitalmars-d mailing list