April 23, 2004
Achilleas Margaritis wrote:
> 
> It is very easy to implement signals and slots in D. The mechanism is the
> same as in C++, with the only difference being that since a D object is not
> deleted unless no other object points to it, you have to manually disconnect
> an object.
> 
> In fact, it is way more easier in D, because of delegates.
> 
> Here is the code for a signal with 1 parameter:
> 
> public class Signal(T) {
>  public alias void delegate(T) Delegate;
> 
>  void exec(T param) {
>     foreach(Delegate dg; m_slots) {
>        dg(param);
>     }
>  }
> 
>  void add(Delegate dg) {
>     m_slots.add(dg);
>  }
> 
>  void remove(Delegate dg) {
>     m_slots.remove(dg);
>  }
> 
>    private List!(Delegate) m_slots;
> }
> 
> Suppose that there is a List template class, the signal becomes a list of
> delegates, with the following interface:
> 
> add(Delegate)
> 
> remove(Delegate)
> 
> exec(T param)
> 
> It can be used like this:
> 
> Signal!(int) callback;
> 
> void proc1(int)
> {
> }
> 
> class Foo {
>     public void action(int i) {
>     }
> }
> 
> //add a function
> callback.add(&proc1);
> 
> //add a method
> Foo foo1 = new Foo;
> callback.add(&foo1.action);
> 
> //call the signal; will call proc1 and foo1.action
> callback(10);
> 
> 

I may be missing something here, but what if we want to delete foo1? Do we need to check all instances of Signal to look for Delegates that should be removed? I guess this needs a Slot object in Norbert's style.
Once I get around to this, it'll be an interesting exercise.

Bastiaan.

April 23, 2004
> I may be missing something here, but what if we want to delete foo1? Do we need to check all instances of Signal to look for Delegates that should be removed? I guess this needs a Slot object in Norbert's style. Once I get around to this, it'll be an interesting exercise.

There are probably several approaches, but personally I'd say whatever registered the delegate should have an API to unregister the same delegate. As previously pointed it is easy to unregister a delegate. The hard/impossible part is taking an arbitrary object and testing if a delegate is a delegate for that object. So design the API to unregister delegates instead of unregsitering objects. That will also cover the cases when the delegates are for stack frames as well as objects.

-Ben


April 23, 2004
That's a neat idea! Very "D-ish"! Just define a .object property on the delegate. It would, of course, be of type "Object".

The Object class could then have two methods
        void connect_notify(Connection) {};
        void disconnect_notify(Connection) {};
that could be overridden by subclasses that want to keep track of
connections that want to have automatic disconnection!

Guess, there we have the full solution for my problem. And I really doubt there are any objections against that ".object" property proposal (ouch, what an evil pun!)

April 23, 2004
As mentioned by others, this really misses the point:

It truely is simple and elegant to construct signals and slots in D. It was just the *disconnection* that gave me trouble. Having to keep track of all connections by hand is rather tedious.

Anyway: The idea by Ben Hinkle really would allow to solve the problem. (See
my other message)


Achilleas Margaritis wrote:

> 
> "Norbert Nemec" <Norbert.Nemec@gmx.de> wrote in message news:c6afc1$2eh6$1@digitaldaemon.com...
>> Hi there,
>>
>> just wondering: has anybody tried to implement a signal/slot mechanism in
> D?
>> I was thinking about it a little, but actually seem to run into trouble:
>>
>> At first sight, delegates seem to solve the problem. Looking closer,
> though,
>> I believe they are insufficient for something in par with Qt's concept signal/slot.
>>
>> A naive implementation is fairly trivial: signals are objects that encapsulate a list of delegates, any non-static class member functions can be seen as slot and connected to signals.
>>
>> One minor drawback here is the rather clumsy syntax needed to declare signals. Lacking templates with variable number of parameters, you would need different signal classes depending on the number of arguments.
>>
>> The far more fundamental problem, though: *disconnecting*.
>>
>> In Qt, every slot knows which signals are connected to it. This makes it possible to disconnect all incoming signals when an object is deactivated (I'm avoiding the term "deleted" here, since in D, deactivation would happen independantly of the deletion that may be done by the GC lateron.)
>>
>> Furthermore, a delegate contains a reference to the object that is binds
> to,
>> but there is no clean way to retrieve that reference from the delegate, so it would not even be possible to include a "deactivated" flag in the class containing the slot and check this before calling it. In the other way around, you might think about checking for the "deactivated" flag inside the slot implementation. But then, you still have no way to disconnect, because from inside the slot you have no way to find out where the signal was that you want to disconnect from.
>>
>> Putting this all together, this means, that with a simple and comfortable implementation using just plain delegates, you have to keep track of all the connections you created in order to be able to disconnect by hand. Otherwise, in a long-running GUI program, with many widgets created and destroyed over time, you would end up with more and more dead connections slowing down everything.
>>
>> If, on the other hand, you implement slots not just as plain routines, but as objects encapsulating a routine, you can, of course, implement this auto-disconnect, but the syntax for slots will get really messy.
>>
>> Any ideas?
>>
>> Ciao,
>> Nobbi
> 
> It is very easy to implement signals and slots in D. The mechanism is the same as in C++, with the only difference being that since a D object is not deleted unless no other object points to it, you have to manually disconnect an object.
> 
> In fact, it is way more easier in D, because of delegates.
> 
> Here is the code for a signal with 1 parameter:
> 
> public class Signal(T) {
>  public alias void delegate(T) Delegate;
> 
>  void exec(T param) {
>     foreach(Delegate dg; m_slots) {
>        dg(param);
>     }
>  }
> 
>  void add(Delegate dg) {
>     m_slots.add(dg);
>  }
> 
>  void remove(Delegate dg) {
>     m_slots.remove(dg);
>  }
> 
>    private List!(Delegate) m_slots;
> }
> 
> Suppose that there is a List template class, the signal becomes a list of delegates, with the following interface:
> 
> add(Delegate)
> 
> remove(Delegate)
> 
> exec(T param)
> 
> It can be used like this:
> 
> Signal!(int) callback;
> 
> void proc1(int)
> {
> }
> 
> class Foo {
>     public void action(int i) {
>     }
> }
> 
> //add a function
> callback.add(&proc1);
> 
> //add a method
> Foo foo1 = new Foo;
> callback.add(&foo1.action);
> 
> //call the signal; will call proc1 and foo1.action
> callback(10);

April 23, 2004
Norbert Nemec wrote:
> Hi there,
> 
> just wondering: has anybody tried to implement a signal/slot mechanism in D?
> I was thinking about it a little, but actually seem to run into trouble:
> 
> At first sight, delegates seem to solve the problem. Looking closer, though,
> I believe they are insufficient for something in par with Qt's concept
> signal/slot.
> 
> A naive implementation is fairly trivial: signals are objects that
> encapsulate a list of delegates, any non-static class member functions can
> be seen as slot and connected to signals.
> 
> One minor drawback here is the rather clumsy syntax needed to declare
> signals. Lacking templates with variable number of parameters, you would
> need different signal classes depending on the number of arguments.

Templates can be overloaded, so you can kinda-sorta work around this. <http://andy.tadan.us/d/Listener.d> (coding it is a bit tedious, but the usage is nice enough)

This doesn't deal with the disconnection thing either, though.

 -- andy
April 23, 2004
How about using something like Weak References.  These are references that allow an object to be garbage collected if it only has weak references left and no others.  The weak reference is set to null when the object is collected.

This has the advantage that delegate would not have to be removed from the signal.

This would mean that the language and garbage collection would have to be modified.

In article <c6bbsk$srp$2@digitaldaemon.com>, Norbert Nemec says...
>
>As mentioned by others, this really misses the point:
>
>It truely is simple and elegant to construct signals and slots in D. It was just the *disconnection* that gave me trouble. Having to keep track of all connections by hand is rather tedious.
>
>Anyway: The idea by Ben Hinkle really would allow to solve the problem. (See
>my other message)
>
>
>Achilleas Margaritis wrote:
>
>> 
>> "Norbert Nemec" <Norbert.Nemec@gmx.de> wrote in message news:c6afc1$2eh6$1@digitaldaemon.com...
>>> Hi there,
>>>
>>> just wondering: has anybody tried to implement a signal/slot mechanism in
>> D?
>>> I was thinking about it a little, but actually seem to run into trouble:
>>>
>>> At first sight, delegates seem to solve the problem. Looking closer,
>> though,
>>> I believe they are insufficient for something in par with Qt's concept signal/slot.
>>>
>>> A naive implementation is fairly trivial: signals are objects that encapsulate a list of delegates, any non-static class member functions can be seen as slot and connected to signals.
>>>
>>> One minor drawback here is the rather clumsy syntax needed to declare signals. Lacking templates with variable number of parameters, you would need different signal classes depending on the number of arguments.
>>>
>>> The far more fundamental problem, though: *disconnecting*.
>>>
>>> In Qt, every slot knows which signals are connected to it. This makes it possible to disconnect all incoming signals when an object is deactivated (I'm avoiding the term "deleted" here, since in D, deactivation would happen independantly of the deletion that may be done by the GC lateron.)
>>>
>>> Furthermore, a delegate contains a reference to the object that is binds
>> to,
>>> but there is no clean way to retrieve that reference from the delegate, so it would not even be possible to include a "deactivated" flag in the class containing the slot and check this before calling it. In the other way around, you might think about checking for the "deactivated" flag inside the slot implementation. But then, you still have no way to disconnect, because from inside the slot you have no way to find out where the signal was that you want to disconnect from.
>>>
>>> Putting this all together, this means, that with a simple and comfortable implementation using just plain delegates, you have to keep track of all the connections you created in order to be able to disconnect by hand. Otherwise, in a long-running GUI program, with many widgets created and destroyed over time, you would end up with more and more dead connections slowing down everything.
>>>
>>> If, on the other hand, you implement slots not just as plain routines, but as objects encapsulating a routine, you can, of course, implement this auto-disconnect, but the syntax for slots will get really messy.
>>>
>>> Any ideas?
>>>
>>> Ciao,
>>> Nobbi
>> 
>> It is very easy to implement signals and slots in D. The mechanism is the same as in C++, with the only difference being that since a D object is not deleted unless no other object points to it, you have to manually disconnect an object.
>> 
>> In fact, it is way more easier in D, because of delegates.
>> 
>> Here is the code for a signal with 1 parameter:
>> 
>> public class Signal(T) {
>>  public alias void delegate(T) Delegate;
>> 
>>  void exec(T param) {
>>     foreach(Delegate dg; m_slots) {
>>        dg(param);
>>     }
>>  }
>> 
>>  void add(Delegate dg) {
>>     m_slots.add(dg);
>>  }
>> 
>>  void remove(Delegate dg) {
>>     m_slots.remove(dg);
>>  }
>> 
>>    private List!(Delegate) m_slots;
>> }
>> 
>> Suppose that there is a List template class, the signal becomes a list of delegates, with the following interface:
>> 
>> add(Delegate)
>> 
>> remove(Delegate)
>> 
>> exec(T param)
>> 
>> It can be used like this:
>> 
>> Signal!(int) callback;
>> 
>> void proc1(int)
>> {
>> }
>> 
>> class Foo {
>>     public void action(int i) {
>>     }
>> }
>> 
>> //add a function
>> callback.add(&proc1);
>> 
>> //add a method
>> Foo foo1 = new Foo;
>> callback.add(&foo1.action);
>> 
>> //call the signal; will call proc1 and foo1.action
>> callback(10);
>


April 23, 2004
Colin JN Breame wrote:

>How about using something like Weak References.  These are references that allow
>an object to be garbage collected if it only has weak references left and no
>others.  The weak reference is set to null when the object is collected.
>
>This has the advantage that delegate would not have to be removed from the
>signal.
>
>This would mean that the language and garbage collection would have to be
>modified.
>

It would be nice if the GC could automaticly null delegates that have objects that no-longer exist.

Well maybe it wouldn't.  Then you'd have all these access violations (which of course you could test for as a performace cost).

-- 
-Anderson: http://badmama.com.au/~anderson/
April 23, 2004
Colin JN Breame wrote:
> How about using something like Weak References.  These are references that allow
> an object to be garbage collected if it only has weak references left and no
> others.  The weak reference is set to null when the object is collected.
> 
> This has the advantage that delegate would not have to be removed from the
> signal.
> 
> This would mean that the language and garbage collection would have to be
> modified.

I'd love to see weak references implemented in D. (be it by altering the language, or implemented by some template wizardry)

 -- andy
April 23, 2004
Colin JN Breame wrote:
> How about using something like Weak References.  These are references that allow
> an object to be garbage collected if it only has weak references left and no
> others.  The weak reference is set to null when the object is collected.
> 

I see two problems:

1) Upon every emit of the signal, all weak delegates would have to be tested for non-nullness.
2) What happens when the receiving object has gone out of scope, but the GC has not yet been run? The object would still receive the signal.

> This has the advantage that delegate would not have to be removed from the
> signal.
> 

The signal could clean itself up, removing delegates that are null. It is not very elegant, though.

> This would mean that the language and garbage collection would have to be
> modified.
> 

I doubt that the advantages of weak delegates are worth such a change.

Bastiaan.

April 23, 2004
J Anderson wrote:
> 
> Well maybe it wouldn't.  Then you'd have all these access violations (which of course you could test for as a performace cost).
> 

Can access violations be cought as an exception?

Bastiaan.