D - Signal/Slot mechanism?
- Norbert Nemec (37/37) Apr 23 2004 Hi there,
- J Anderson (167/206) Apr 23 2004 Workaround: Put everything into a struct. You an even then add methods...
- Norbert Nemec (18/25) Apr 23 2004 OK, that is some kind of a solution: say that signals/slots always have
- Bastiaan Veelo (7/55) Apr 22 2004 I have not tried yet, but I have thought of porting libsigc++ to D as a
- Stephan Wienczny (2/11) Apr 23 2004 Is there something I can do in C++, I can't do in D?
- Norbert Nemec (7/20) Apr 23 2004 Well - the template mechanism is completely different, so for many thing...
- Norbert Nemec (20/20) Apr 23 2004 Hey, I guess I should have looked at libsigc++ earlier. It really give m...
- Achilleas Margaritis (47/84) Apr 23 2004 D?
- J Anderson (4/47) Apr 23 2004 This is basicly the dig thing I posted before.
- Bastiaan Veelo (6/69) Apr 23 2004 I may be missing something here, but what if we want to delete foo1? Do
- Ben Hinkle (8/12) Apr 23 2004 There are probably several approaches, but personally I'd say whatever
- Norbert Nemec (7/122) Apr 23 2004 As mentioned by others, this really misses the point:
- Colin JN Breame (8/130) Apr 23 2004 How about using something like Weak References. These are references th...
- J Anderson (7/14) Apr 23 2004 It would be nice if the GC could automaticly null delegates that have
- Bastiaan Veelo (3/7) Apr 23 2004 Can access violations be cought as an exception?
- Andy Friesen (4/13) Apr 23 2004 I'd love to see weak references implemented in D. (be it by altering the...
- Bastiaan Veelo (10/20) Apr 23 2004 I see two problems:
- Achilleas Margaritis (31/36) Apr 23 2004 You just have to make a superclass for all objects that have slots:
- Ben Hinkle (23/26) Apr 23 2004 [snip]
- Norbert Nemec (10/10) Apr 23 2004 That's a neat idea! Very "D-ish"! Just define a .object property on the
- Andy Friesen (6/22) Apr 23 2004 Templates can be overloaded, so you can kinda-sorta work around this.
- Norbert Nemec (4/8) Apr 23 2004 Hey, thanks - nice to know that this works. I thought about it, but didn...
- Achilleas Margaritis (14/29) Apr 23 2004 See my other post for the disconnection problem. Basically, it involves
- Walter (8/18) Apr 23 2004 ugly,
- Achilleas Margaritis (111/134) Apr 24 2004 different
- J Anderson (6/14) Apr 24 2004 I think signals and slots could be implemented neatly in a library if
- Achilleas Margaritis (2/6) Apr 25 2004 There is also the problem of names: it is ugly to have signal0, signal1,
- Norbert Nemec (5/13) Apr 25 2004 That's not a problem in D: you can have templates with different number ...
- Achilleas Margaritis (12/16) Apr 25 2004 D is even cooler than I thought. :-)
- Norbert Nemec (13/32) Apr 25 2004 Yes, true, we need to copy/paste for every number of arguments. I doubt,...
- Colin JN Breame (3/141) Apr 25 2004 Seconded - this is exactly how it should work. Any idea how we can get ...
- J Anderson (5/8) Apr 25 2004 Put something up on
- Norbert Nemec (19/20) Apr 24 2004 Signals and Slots are a concept that becomes useful especially in RAD (r...
- Ben Hinkle (19/27) Apr 23 2004 I can't see what is so hard about removing a delegate that it requires
- Norbert Nemec (10/18) Apr 24 2004 I like that analogy! The difficulty I was talking about would be: What i...
- lgoss007 yahoo.com (10/10) Oct 20 2005 Well this thread is kind of old, but I'm somewhat interested in this
- nick (9/24) Feb 08 2006 Start here:
- diablito bk.ru (142/142) Jul 16 2006 Like this
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
Apr 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.Workaround: Put everything into a struct. You an even then add methods to the struct to give it more power (to do generally things with it's contained variables) then just passing in a group of variable 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, NobbiI don't know how helpful this will be but dig uses a dispatcher. And add the event to a class like struct rect { int x, y; //Other methods that apply } class A { DispatcherT!(rect).Dispatcher onResized; ... Called when resize occurs rect r; r.x = x; r.y = y; onResized.notify(r); ... } In this example you can declare an event like: class A { this() { onResized.add(&resize); } void resize(rect r) { ... } } //Note : opCalls simplify the syntax even more (but I didn't use them in this example). ////////////////////////////////////////////////////////////////////// /*! * \file * \brief * \author BurtonRadons (modified by Charles Sanders and Joel Anderson) * \version 1.0 * \date 4 / 9 / 2004 */ ////////////////////////////////////////////////////////////////////// template DispatcherT(Event) { /** A set of delegates that are notified when a a Control event is activated. */ struct Dispatcher { alias void delegate (Event event) Method; /**< The first-form method. */ alias void delegate () MethodB; /**< The second-form method. */ Method [] methods; /**< The list of methods called by notify. */ MethodB [] methodbs; /**< No-argument-form methods. */ Dispatcher *[] dispatchers; /**< Dispatcher pointers. */ /** Add a method to the list. Frees the previous list if append resulted in re-allocation. */ void add(Method method) { methods ~= method; } /** Add a no-argument-form method to the list. */ void add(MethodB method) { methodbs ~= method; } /** Add a dispatcher pointer to the list. */ void add(Dispatcher *dispatcher) { dispatchers ~= dispatcher; } /** Remove a method from the list. */ void remove (Method m) { for (int c; c < methods.length; c ++) if (m == methods [c]) { for ( ; c < methods.length - 1; c ++) methods [c] = methods [c + 1]; methods.length = methods.length - 1; } } /** Remove a method from the list. */ void remove (MethodB m) { for (int c; c < methodbs.length; c ++) if (m == methodbs [c]) { for ( ; c < methodbs.length - 1; c ++) methodbs [c] = methodbs [c + 1]; methodbs.length = methodbs.length - 1; } } /** Remove a dispatcher from the list. */ void remove (Dispatcher *d) { for (int c; c < dispatchers.length; c ++) if (d == dispatchers [c]) { for ( ; c < dispatchers.length - 1; c ++) dispatchers [c] = dispatchers [c + 1]; dispatchers.length = dispatchers.length - 1; } } /** Notify the methods that an event has occured. */ void notify (Event e) { for (Method *m = methods, n = m + methods.length; m < n; m ++) (*m) (e); for (MethodB *m = methodbs, n = m + methodbs.length; m < n; m ++) (*m) (); for (Dispatcher **m = dispatchers, n = m + dispatchers.length; m < n; m ++) (*m).notify (e); } /** Notify the methods with an empty event. */ void notify () { Event e; notify (e); } /** Notify this dispatcher if non-empty, or the other dispatcher if this one is. */ void notifyOrEmpty (Event e, Dispatcher *other) { if (methods.length) notify (e); else other.notify (e); } /** Notify this dispatcher if non-empty, or the other dispatcher if this one is. */ void notifyOrEmpty (Dispatcher *other) { Event e; notifyOrEmpty (e, other); } /** Return whether there are no entries in this dispatcher. */ bit isEmpty () { return methods.length == 0 && methodbs.length == 0 && dispatchers.length == 0; } /** Notify the methods with an empty event. */ void opCall() { notify(); } /** Notify the methods that an event has occured. */ void opCall(Event e) { notify(e); } /** Add a method to the list. Frees the previous list if append resulted in re-allocation. */ void opCall(Method method) { add(method); } /** Add a no-argument-form method to the list. */ void opCall(MethodB method) { add(method); } /** Add a dispatcher pointer to the list. */ void opCall(Dispatcher *dispatcher) { add(dispatcher); } } } -- -Anderson: http://badmama.com.au/~anderson/
Apr 23 2004
J Anderson wrote:Norbert Nemec wrote: Workaround: Put everything into a struct. You an even then add methods to the struct to give it more power (to do generally things with it's contained variables) then just passing in a group of variable arguments.OK, that is some kind of a solution: say that signals/slots always have exactly one argument of arbitrary type and then use a struct instead of multiple arguments. But anyway that's just a minor problem.That doesn't help at all. "dispatcher" basically is just another term for what Qt calls signal. The core problem stays there: You create your widgets and connect them wildly by adding delegates to dispatchers. Now you want to delete one widget. Along with it, you want to cut all the connections to it. To do so, you have to keep track of all the connections you created earlier. I don't see any way to do so automatically in some comfortable way. And doing it by hand causes similar problems as the manual memory management in C++. If you forget to cut some connection, you may have deleted the widget, but the connected routine will still be called and the GC will not be able to clean up the widget object. For simple, rather static programs, that is no big issue, but for big, long-running applications, you will collect lots of garbage and the program will get slower and slower because of all the calls to stale connections.The far more fundamental problem, though: *disconnecting*.I don't know how helpful this will be but dig uses a dispatcher.
Apr 23 2004
I have not tried yet, but I have thought of porting libsigc++ to D as a way to learn D. It will have to wait until the autumn though, as I am tied up at the moment. Do you know that library? Does it use template functionality that is not in D? http://libsigc.sourceforge.net/ Bastiaan. 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. 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
Apr 22 2004
Bastiaan Veelo wrote:I have not tried yet, but I have thought of porting libsigc++ to D as a way to learn D. It will have to wait until the autumn though, as I am tied up at the moment. Do you know that library? Does it use template functionality that is not in D? http://libsigc.sourceforge.net/ Bastiaan.Is there something I can do in C++, I can't do in D?
Apr 23 2004
Stephan Wienczny wrote:Bastiaan Veelo wrote:Well - the template mechanism is completely different, so for many things you will at least have to do them differently. libsigc++ really squeezes everything out of the C++-template mechanism, so it is hard to tell where you might find yet-unknown limitations of D. B.t.w: I have no doubt you can do everything in D - the question only is whether it is still comfortable and efficient.I have not tried yet, but I have thought of porting libsigc++ to D as a way to learn D. It will have to wait until the autumn though, as I am tied up at the moment. Do you know that library? Does it use template functionality that is not in D? http://libsigc.sourceforge.net/ Bastiaan.Is there something I can do in C++, I can't do in D?
Apr 23 2004
Hey, I guess I should have looked at libsigc++ earlier. It really give me the idea of a solution: If you introduce a class "Slot", then of course, it could take two arguments as constructor arguments: a delegate and, additionally, a reference to the object that the delegate points to. OK, it looks a bit strange at first: sigsomething.connect(Slot(someobject,&(someobject.routine)) (in C++ this could be solved by a macro, which we don't have in D) and actually, you pass the same pointer twice, but what the heck - it allows you to implement that automatic disconnection, since the Slot creator could simply register itself in someobject - which of course has to inherit from some basic class. Porting libsigc++ to D would definitely be something very interesting. I guess you really have to dig into the language. If any necessary functionality in D is missing it would be highly interesting to investigate. Anyhow: I would suggest not to try to stick to libsigc++ too closely. Pick up the concepts and ideas and then see how you can do something at least as good in D. I guess, you can even surpass what libsigc++ is doing, since D just has a number of very powerful features.
Apr 23 2004
"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 inD?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 bindsto,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, NobbiIt 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);
Apr 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);This is basicly the dig thing I posted before. -- -Anderson: http://badmama.com.au/~anderson/
Apr 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.
Apr 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
Apr 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 inD?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 bindsto,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, NobbiIt 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);
Apr 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 inD?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 bindsto,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, NobbiIt 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);
Apr 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/
Apr 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.
Apr 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
Apr 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.
Apr 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.You just have to make a superclass for all objects that have slots: class SlotContainer { public ~this() { clearSlots(); } public addSlot(Slot slot); public removeSlot(Slot slot); public void clearSlots() { delete all slots; } } The signal would add a slot to the object: class Signal { public void add(SlotContainer container, void delegate(T) dg) { m_slots.add(dg); Slot slot = new Slot(dg); slot.m_signals.add(this); container.addSlot(slot); } } When the slot is deleted, it removes itself from all the signals it belongs: class Slot { public ~this() { foreach(Signal sig ; m_signals) { sig.remove(this); } } } Then, each time a SlotContainer-derived object is deleted, it will also delete all its slots, and the slots would unregister themselves from the objects they are registered into.
Apr 23 2004
[snip]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[snip] It would be nice to have a few properties on delegates to split it apart. One wrinkle is that delegates can also use stack frames as the "object" so any return type of a property for the object would have to return void* or something like that. A "temporary" workaround is to delve into implementation specific hackery: struct DelegateStruct { void* frame_or_obj; void* fcn; } class Foo { void foo() { } } int main() { Foo x = new Foo(); void delegate () y = &x.foo; DelegateStruct *y2 = (DelegateStruct*)&y; printf("x=%p, y2.frame_or_obj=%p\n",x,y2.frame_or_obj); return 0; }
Apr 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!)
Apr 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
Apr 23 2004
Andy Friesen wrote: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)Hey, thanks - nice to know that this works. I thought about it, but didn't try it yet.This doesn't deal with the disconnection thing either, though.For that, I have the solution as well, now.
Apr 23 2004
Norbert Nemec wrote:Andy Friesen wrote:See my other post for the disconnection problem. Basically, it involves registering the slot to the signal and the signal to the slot. When the slot's owner is deleted, the slot is deleted, thus removing itself from the signal. But I wanted to say something, here, to Walter: Walter, signals and slots need support at language level. Templates are ugly, and one has to provide lots of different template classes, with different names, for each number of parameters. Signals and slots should follow delegate syntax, using the keyword 'signal', like this: ReturnType signal ( Arguments ) Identifier ; Signals should contain weak references, as mentioned above, and when the objects that are registered to signals are deleted, slots are automatically deleted. It is an important functionality Walter, please don't ignore it.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)Hey, thanks - nice to know that this works. I thought about it, but didn't try it yet.This doesn't deal with the disconnection thing either, though.For that, I have the solution as well, now.
Apr 23 2004
"Achilleas Margaritis" <axilmar b-online.gr> wrote in message news:c6c32m$2447$1 digitaldaemon.com...But I wanted to say something, here, to Walter: Walter, signals and slots need support at language level. Templates areugly,and one has to provide lots of different template classes, with differentnames,for each number of parameters. Signals and slots should follow delegate syntax, using the keyword'signal',like this: ReturnType signal ( Arguments ) Identifier ; Signals should contain weak references, as mentioned above, and when theobjectsthat are registered to signals are deleted, slots are automaticallydeleted.It is an important functionality Walter, please don't ignore it.Frankly, I don't understand signals and slots at all.
Apr 23 2004
"Walter" <walter digitalmars.com> wrote in message news:c6ca6t$2g9a$1 digitaldaemon.com..."Achilleas Margaritis" <axilmar b-online.gr> wrote in message news:c6c32m$2447$1 digitaldaemon.com...differentBut I wanted to say something, here, to Walter: Walter, signals and slots need support at language level. Templates areugly,and one has to provide lots of different template classes, withnames,If you don't mind me explaining it, here is a short explanation: A signal is a list of callbacks. When a signal is called, all the callbacks are called in the order that they are registered. A callback is either a function or a method...in other words, a delegate. Callbacks can be arbitrarily added and removed to one or more signals. In some libraries (Qt for example), a function or method has to be explicitly marked as a callback, otherwise it can not be added to a signal. This 'marking' turns a callback to a 'slot', i.e. an explicitly defined signal target. The addition of a slot/callback/delegate/whatever to a signal is called a 'connection'. The removal of a slot/callback/delegate/whatever from a signal is called a 'disconnection'. Here is an example: A dialog has two methods 'accept' and 'reject', called when the user presses ok/enter or cancel/escape respectively. A PushButton class contains a 'click' signal: when the user clicks the button, this signal is called. The best and easiest way to connect a pushbutton with a dialog is to have 2 pushbuttons, one for the ok and one for the cancel case. The dialog's accept method is connected to the ok button's click signal; the dialog's reject method is connected to the cancel button's click signal. Now, when the user presses the ok button, the dialog's accept method is called, and the dialog is accepted. When the user presses the cancel button, the dialog's reject method is called, and the dialog is rejected. The signals and slots mechanism is the best way to manage the model-view-controller pattern: a) the model contains signals about when it is modified. b) the view contains slots to update the display when the model changes. c) the controller fires signals of the model, by modifying the model. The most important property of the signals and slots mechanism is that objects are not aware of the presence of other objects. In other words, a pushbutton does not need to know anything about the presence of a dialog. The pushbutton just says 'click' to the outside world, and whoever is listening takes action. Signals and slots can be done with C++ templates, but you need one template for each number of parameters that exist. That is why libsig++ or boost have classes like signal0, signal1, signal2, signal3 etc for 0, 1, 2, 3 or more parameters. Objects that have methods which can be slots must inherit from a specific class, which keeps track of which slots belong to which objects and automatically removes the slots from their signals when deleted. Java has anonymous functions: each object (let's say a pushbutton) executes a specific function which usually belongs to some other object (let's say a dialog). Anonymous functions are coded inline at the place of event instantiation. This is an ugly solution, because a class becomes a huge file with functions spreaded here and there. Sun has been critisized for it a lot. like this: event click(int data); And then you add and delete methods to it, like this: click += dialog.accept; This is an elegant solution, but it requires for the destination object to keep track where it has added its methods, so it can remove them when no longer used. What we are asking from you, Walter, is to provide a signal and slot but it also allows for automatic removal of slots when an object is deleted, ala C++. If you don't mind, let me give you my view about how the syntax of signals and slots should be: signal Identifier ( Arguments ) ; The signal word should be a keyword. The following operations should be allowed on signals: signal += (delegate); signal -= (delegate); signal(Arguments); The operator += adds a delegate to a signal (only if it has not been added yet, of course); the operator -= removes a delegate from a signal; the operator () calls the signal with the given arguments. Here is the implementation: A signal is a linked list of delegates. Each time operator += is called, a delegate is added to the linked list of delegates the signal contains. Each time operator -= is called, a delegate is removed from the linked list of delegates. When the signal is called, the linked list of delegates is traversed and each delegate is called. Here is the important detail, concering delegates that are methods: The Object class should contain a linked list of pointers to delegates. each time a delegate is added to the signal, a pointer to the delegate is added to the Object-derived object. This pointer is not checked by the garbage collector (it is a weak reference). When the object is deleted, the delegates that the object contains are automatically removed from the signals they belong. In this way, an Object does not have to track in which signals it is registered to. Please, Walter, take this into consideration. I would not have spent so much time, carefully handcrafting this post, if it was not important. D is the best language there is, and the mechanisms are there for the signals and slots mechanism to be implemented(from what I have seen of the dmd sources). It would take you a couple of hours to implement it, but it will save thousands of hours of frustration from D programmers. You say in the documentation that some things are better be part of the language, instead of being done by libraries. You added 'complex' and 'map' (associative array) to the language for this reason. But signals and slots are much more important than either complex and map, I think that they should be part of the language, for elegance...it is one of those mechanisms, that has to be part of D. Don't hesitate to ask me anything about signals and slots...I will be more than happy to answer.for each number of parameters. Signals and slots should follow delegate syntax, using the keyword'signal',like this: ReturnType signal ( Arguments ) Identifier ; Signals should contain weak references, as mentioned above, and when theobjectsthat are registered to signals are deleted, slots are automaticallydeleted.It is an important functionality Walter, please don't ignore it.Frankly, I don't understand signals and slots at all.
Apr 24 2004
Achilleas Margaritis wrote:You say in the documentation that some things are better be part of the language, instead of being done by libraries. You added 'complex' and 'map' (associative array) to the language for this reason. But signals and slots are much more important than either complex and map, I think that they should be part of the language, for elegance...it is one of those mechanisms, that has to be part of D.I think signals and slots could be implemented neatly in a library if some language support was provided for removing delegates that reference objects that no-longer exist. -- -Anderson: http://badmama.com.au/~anderson/
Apr 24 2004
There is also the problem of names: it is ugly to have signal0, signal1, signal2 etc.I think signals and slots could be implemented neatly in a library if some language support was provided for removing delegates that reference objects that no-longer exist.
Apr 25 2004
Achilleas Margaritis wrote:That's not a problem in D: you can have templates with different number of parameters but the same name, and even templates with zero arguments. (A non-templated class would clash with the name of a template, but a zero-parameter class can have the same name as a one-parameter class)There is also the problem of names: it is ugly to have signal0, signal1, signal2 etc.I think signals and slots could be implemented neatly in a library if some language support was provided for removing delegates that reference objects that no-longer exist.
Apr 25 2004
That's not a problem in D: you can have templates with different number of parameters but the same name, and even templates with zero arguments. (A non-templated class would clash with the name of a template, but a zero-parameter class can have the same name as a one-parameter class)D is even cooler than I thought. :-) Anyway, a signals and slots mechanism not supported by the language also has other problems: 1) one has to cater for the different number of parameters. Libsig++ has 20 template signals, all doing the same thing. 2) objects should inherit from a specific class that knows about how to get rid of slots when deleted. If they don't inherit from the class, they can't be connected to slots. 3) specifically for garbage collected languages, object pointers in slots must not be garbage collected; otherwise, the GC will never delete the objects, unless the slots are explicitely removed from their signals, which is not desired.
Apr 25 2004
Achilleas Margaritis wrote:Yes, true, we need to copy/paste for every number of arguments. I doubt, 20 would be necessary, though...That's not a problem in D: you can have templates with different number of parameters but the same name, and even templates with zero arguments. (A non-templated class would clash with the name of a template, but a zero-parameter class can have the same name as a one-parameter class)D is even cooler than I thought. :-) Anyway, a signals and slots mechanism not supported by the language also has other problems: 1) one has to cater for the different number of parameters. Libsig++ has 20 template signals, all doing the same thing.2) objects should inherit from a specific class that knows about how to get rid of slots when deleted. If they don't inherit from the class, they can't be connected to slots.True, lacking multiple inheritance, you have to put that code right into the base of any class hierarchy you build. Alternatively, you can use an interface that slot-aware objects have to implement to get auto-disconnection. Not too much of a problem: you would put that code way up in the hierarchy of any library anyway.3) specifically for garbage collected languages, object pointers in slots must not be garbage collected; otherwise, the GC will never delete the objects, unless the slots are explicitely removed from their signals, which is not desired.True, from the GC point of view, signal-slot-connections should be handled as one-way pointers, even if the implementation needs pointers in both directions to enable auto-disconnection. Maybe there should be a way to specify pointers that should not be traversed, when the garbage collector marks life objects?
Apr 25 2004
Seconded - this is exactly how it should work. Any idea how we can get Walter to take a look at this proposal? In article <c6ehdg$1vkk$1 digitaldaemon.com>, Achilleas Margaritis says..."Walter" <walter digitalmars.com> wrote in message news:c6ca6t$2g9a$1 digitaldaemon.com..."Achilleas Margaritis" <axilmar b-online.gr> wrote in message news:c6c32m$2447$1 digitaldaemon.com...differentBut I wanted to say something, here, to Walter: Walter, signals and slots need support at language level. Templates areugly,and one has to provide lots of different template classes, withnames,If you don't mind me explaining it, here is a short explanation: A signal is a list of callbacks. When a signal is called, all the callbacks are called in the order that they are registered. A callback is either a function or a method...in other words, a delegate. Callbacks can be arbitrarily added and removed to one or more signals. In some libraries (Qt for example), a function or method has to be explicitly marked as a callback, otherwise it can not be added to a signal. This 'marking' turns a callback to a 'slot', i.e. an explicitly defined signal target. The addition of a slot/callback/delegate/whatever to a signal is called a 'connection'. The removal of a slot/callback/delegate/whatever from a signal is called a 'disconnection'. Here is an example: A dialog has two methods 'accept' and 'reject', called when the user presses ok/enter or cancel/escape respectively. A PushButton class contains a 'click' signal: when the user clicks the button, this signal is called. The best and easiest way to connect a pushbutton with a dialog is to have 2 pushbuttons, one for the ok and one for the cancel case. The dialog's accept method is connected to the ok button's click signal; the dialog's reject method is connected to the cancel button's click signal. Now, when the user presses the ok button, the dialog's accept method is called, and the dialog is accepted. When the user presses the cancel button, the dialog's reject method is called, and the dialog is rejected. The signals and slots mechanism is the best way to manage the model-view-controller pattern: a) the model contains signals about when it is modified. b) the view contains slots to update the display when the model changes. c) the controller fires signals of the model, by modifying the model. The most important property of the signals and slots mechanism is that objects are not aware of the presence of other objects. In other words, a pushbutton does not need to know anything about the presence of a dialog. The pushbutton just says 'click' to the outside world, and whoever is listening takes action. Signals and slots can be done with C++ templates, but you need one template for each number of parameters that exist. That is why libsig++ or boost have classes like signal0, signal1, signal2, signal3 etc for 0, 1, 2, 3 or more parameters. Objects that have methods which can be slots must inherit from a specific class, which keeps track of which slots belong to which objects and automatically removes the slots from their signals when deleted. Java has anonymous functions: each object (let's say a pushbutton) executes a specific function which usually belongs to some other object (let's say a dialog). Anonymous functions are coded inline at the place of event instantiation. This is an ugly solution, because a class becomes a huge file with functions spreaded here and there. Sun has been critisized for it a lot. like this: event click(int data); And then you add and delete methods to it, like this: click += dialog.accept; This is an elegant solution, but it requires for the destination object to keep track where it has added its methods, so it can remove them when no longer used. What we are asking from you, Walter, is to provide a signal and slot but it also allows for automatic removal of slots when an object is deleted, ala C++. If you don't mind, let me give you my view about how the syntax of signals and slots should be: signal Identifier ( Arguments ) ; The signal word should be a keyword. The following operations should be allowed on signals: signal += (delegate); signal -= (delegate); signal(Arguments); The operator += adds a delegate to a signal (only if it has not been added yet, of course); the operator -= removes a delegate from a signal; the operator () calls the signal with the given arguments. Here is the implementation: A signal is a linked list of delegates. Each time operator += is called, a delegate is added to the linked list of delegates the signal contains. Each time operator -= is called, a delegate is removed from the linked list of delegates. When the signal is called, the linked list of delegates is traversed and each delegate is called. Here is the important detail, concering delegates that are methods: The Object class should contain a linked list of pointers to delegates. each time a delegate is added to the signal, a pointer to the delegate is added to the Object-derived object. This pointer is not checked by the garbage collector (it is a weak reference). When the object is deleted, the delegates that the object contains are automatically removed from the signals they belong. In this way, an Object does not have to track in which signals it is registered to. Please, Walter, take this into consideration. I would not have spent so much time, carefully handcrafting this post, if it was not important. D is the best language there is, and the mechanisms are there for the signals and slots mechanism to be implemented(from what I have seen of the dmd sources). It would take you a couple of hours to implement it, but it will save thousands of hours of frustration from D programmers. You say in the documentation that some things are better be part of the language, instead of being done by libraries. You added 'complex' and 'map' (associative array) to the language for this reason. But signals and slots are much more important than either complex and map, I think that they should be part of the language, for elegance...it is one of those mechanisms, that has to be part of D. Don't hesitate to ask me anything about signals and slots...I will be more than happy to answer.for each number of parameters. Signals and slots should follow delegate syntax, using the keyword'signal',like this: ReturnType signal ( Arguments ) Identifier ; Signals should contain weak references, as mentioned above, and when theobjectsthat are registered to signals are deleted, slots are automaticallydeleted.It is an important functionality Walter, please don't ignore it.Frankly, I don't understand signals and slots at all.
Apr 25 2004
Colin JN Breame wrote:Seconded - this is exactly how it should work. Any idea how we can get Walter to take a look at this proposal?Put something up on http://www.prowiki.org/wiki4d/wiki.cgi?FeatureRequestList. -- -Anderson: http://badmama.com.au/~anderson/
Apr 25 2004
Walter wrote:Frankly, I don't understand signals and slots at all.Signals and Slots are a concept that becomes useful especially in RAD (rapid applcation development): You have many components boxed up and just tie them together to a program. Especially in GUI-development: There you have all kinds of widgets everyone defining some signals and some slots. To put together a program, you just create all the widgets you need, set their properties (color, position, text, etc.) and connect their signals and slots. For writing non-interactive programs, there is little reason to use that concept. For interactive, event-driven programming, though, it is the best invention since sliced bread. The core point that distinguishes the signal/slot concept from plain callbacks is, that the connection is not initiated neither by the sender nor by the receiver. The sender just offers a signal, the receiver offers a slot and the application-programmer connect the two lateron. This is, why it is important to have some mechanism to keep track of all the connections that were created. Nobody really is responsible for connections and still they have to be cleanly removed once one of the parties goes out of business.
Apr 24 2004
Walter, signals and slots need support at language level. Templates are ugly, and one has to provide lots of different template classes, with different names, for each number of parameters. Signals and slots should follow delegate syntax, using the keyword 'signal', like this: ReturnType signal ( Arguments ) Identifier ; Signals should contain weak references, as mentioned above, and when the objects that are registered to signals are deleted, slots are automatically deleted.I can't see what is so hard about removing a delegate that it requires language support. By analogy consider an email majordomo list with a list of subscribers. If someone subscribed to the list wants out (either because they just don't want to get the email anymore or because they are about to ... umm... be deleted and want to put their affairs in order), they unsubscribe from the list. It seems pretty simple. Should the slot be cleared if it asserts, say, 10 times in a row? Just because an object has a weak reference you still don't know when it is no longer in use. There is an unknown period of time between when the object becomes garbage and when it gets collected. In any case what about the delegates that don't have object references but use a stack frame? Should they get automatically deleted, too? The greatest benefit to adding language support would be to avoid templates and provide some syntactic sugar - at least with the implementations presented so far. I don't know all that much about unregistering smarts but it does make it easier to define events and maintain lists of callbacks.
Apr 23 2004
Ben Hinkle wrote:I can't see what is so hard about removing a delegate that it requires language support. By analogy consider an email majordomo list with a list of subscribers. If someone subscribed to the list wants out (either because they just don't want to get the email anymore or because they are about to ... umm... be deleted and want to put their affairs in order), they unsubscribe from the list. It seems pretty simple.I like that analogy! The difficulty I was talking about would be: What if you lost track over what lists you are subscribed to? If, in addition, the messages don't show where they came from, your Mailbox will be flooded and there is little you can do. The problem actually is there, since anybody can create subscriptions, (i.e. connections) Anyhow: your own idea with that .object property would solve the problem, since it would give the mailing list a handle to send a control message to the receiver at subscription time. Now you just collect these control messages and know where you get the messages from.
Apr 24 2004
Well this thread is kind of old, but I'm somewhat interested in this events (which are delegates with a few special constranints/feautures): http://blog.monstuff.com/archives/000040.html And here is a simple use of events for non-gui use (a metranome): http://www.codeproject.com/csharp/SimplestEventExample.asp I've read that this kind of thing can be done in D, so what would be a simple way to do this in D (I'm still kind of new to D)? Thanks, Lucas
Oct 20 2005
lgoss007 yahoo.com wrote:Well this thread is kind of old, but I'm somewhat interested in this events (which are delegates with a few special constranints/feautures): http://blog.monstuff.com/archives/000040.html And here is a simple use of events for non-gui use (a metranome): http://www.codeproject.com/csharp/SimplestEventExample.asp I've read that this kind of thing can be done in D, so what would be a simple way to do this in D (I'm still kind of new to D)? Thanks, LucasStart here: http://www.digitalmars.com/d/type.html#delegates search for the word delegate in this page for some examples: http://www.digitalmars.com/d/expression.html also on this page: http://www.digitalmars.com/d/statement.html and just try it things with DMD until it works. Goodluck
Feb 08 2006
Like this Module ss.d typedef void delegate(...) SIGNAL; typedef void delegate(...) SLOT; struct SIGNAL_SLOT { SIGNAL _in; SLOT _out; } struct SIGNAL_SIGNAL { SIGNAL _in; SIGNAL _out; } extern (D) SIGNAL_SLOT[int] signal_slot; extern (D) SIGNAL_SIGNAL[int] signal_signal; static class SS { //************************************************************************** static void connect(SIGNAL _in, SLOT _out) { int index = -1; int keys[] = signal_slot.keys; foreach (int key; keys) { if (signal_slot[key]._in==_in && signal_slot[key]._out==_out ) { index = key; break; } } if (index==-1) { SIGNAL_SLOT tmp; tmp._in = _in; tmp._out = _out; signal_slot[signal_slot.length+1] = tmp; } } //************************************************************************** static void connect2(SIGNAL _in, SIGNAL _out) { if (_in==_out){return;} int index = -1; int keys[] = signal_signal.keys; foreach (int key; keys) { if (signal_signal[key]._in==_in && signal_signal[key]._out==_out ) { index = key; break; } } if (index==-1) { SIGNAL_SIGNAL tmp; tmp._in = _in; tmp._out = _out; signal_signal[signal_signal.length+1] = tmp; } } //************************************************************************** static void disconnect(SIGNAL _in, SLOT _out) { int keys[] = signal_slot.keys; foreach (int key; keys) { if (signal_slot[key]._in==_in && signal_slot[key]._out==_out ) { signal_slot.remove(key); break; } } } //************************************************************************** static void disconnect2(SIGNAL _in, SIGNAL _out) { int keys[] = signal_signal.keys; foreach (int key; keys) { if (signal_signal[key]._in==_in && signal_signal[key]._out==_out ) { signal_signal.remove(key); break; } } } //************************************************************************** static void signal(SIGNAL _in, void *_argptr, TypeInfo[] _arguments) { int keys[] = signal_slot.keys; foreach (int key; keys) { if (signal_slot[key]._in==_in ) { signal_slot[key]._out(_argptr,_arguments); } } int keys2[] = signal_signal.keys; foreach (int key; keys2) { if (signal_signal[key]._in==_in ) { //signal_signal[key]._out(_argptr,_arguments); } } } } How use import ss; class test { this(){} ~this(){} void signal(...) { printf("signal\n"); SS.signal(&this.signal,_argptr,_arguments); } void signal2(...) { printf("signal2\n"); SS.signal(&this.signal2,_argptr,_arguments); } void slot(...) { printf("slot\n"); } void slot2(...) { printf("slot2\n"); } } void f(int f) { test t = new test(); SS.connect(&t.signal, &t.slot); SS.connect(&t.signal2, &t.slot2); SS.connect(&t.signal, &t.signal2); t.signal(); delete t; }
Jul 16 2006