digitalmars.D.announce - signal slots (new, fixed version)
- Lutger (37/37) Oct 27 2006 After Bastiaan Veelo's post I realized my signal slots library should be...
- Bill Baxter (14/61) Oct 30 2006 It seems like having a return value in the slot that differs from the
- Lutger (21/36) Oct 30 2006 I simply didn't think of that, thanks. The connection should fail with a...
- Kristian (9/21) Nov 01 2006 [snip]
- Thomas Kuehne (11/16) Nov 01 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Lutger (6/29) Nov 01 2006 Oh crap I wish I knew about this undocumented feature before. Thank you
- Sean Kelly (3/32) Nov 01 2006 It was added in DMD 170-172, so it hasn't been around for long.
- Walter Bright (3/12) Nov 01 2006 It was added to support signals and slots, which will be in the next
- J Duncan (5/20) Nov 01 2006 You are the man! I have been experimenting with hooking into object
- Walter Bright (11/16) Nov 01 2006 I looked into that, too, and decided that it was never going to work.
- Sean Kelly (10/26) Nov 01 2006 I agree. Ares allows object destruction in general to be hooked, but
- Lutger (5/20) Nov 01 2006 Now that is great! Didn't expect this so soon, I'll wait until then to
- Bill Baxter (4/19) Nov 01 2006 Wow! Excellent. Any chance you'll run the API by the newsgroup for
- Walter Bright (2/4) Nov 01 2006 I'd like to wait a bit first, I'm not ready yet.
After Bastiaan Veelo's post I realized my signal slots library should be rewritten, which is now mostly done. You can get the result or browse the docs here: lutger.ifastnet.com Unreferenced objects are now properly garbage collected and disconnected, emitting a signal (should) incurs less overhead, both memory- and performance wise. It still needs some testing and a little work, but it's functional. Features: - free functions, delegate literals and delegates can act as slots - clean syntax, freestanding signals. - emitting signals are locked to prevent possible stack overflow, can be turned off with version=Unsafe. - can set a default handler, which is invoked when a signal is emitted that has no slots connected. - signals can have return values. - signals have opApply and opApplyReverse for custom iteration, mapping and combining return values. Example: import std.stdio, sslot.signal; class Button { this() { onClick = new Signal!(); } Signal!() onClick; } class Receiver : ISlotTracking { void handleClick() { writefln("button clicked"); } mixin SlotTracking; } Button button = new Button; Receiver receiver = new Receiver; button.onClick.connect(&receiver.handleClick, receiver); button.onClick(); // prints 'button clicked' Signal!(int,int) signal = new Signal!(int,int); signal ~= (int num) { return num * num; }; assert(signal(3) == 9);
Oct 27 2006
Lutger wrote:After Bastiaan Veelo's post I realized my signal slots library should be rewritten, which is now mostly done. You can get the result or browse the docs here: lutger.ifastnet.com Unreferenced objects are now properly garbage collected and disconnected, emitting a signal (should) incurs less overhead, both memory- and performance wise. It still needs some testing and a little work, but it's functional. Features: - free functions, delegate literals and delegates can act as slots - clean syntax, freestanding signals. - emitting signals are locked to prevent possible stack overflow, can be turned off with version=Unsafe. - can set a default handler, which is invoked when a signal is emitted that has no slots connected. - signals can have return values. - signals have opApply and opApplyReverse for custom iteration, mapping and combining return values. Example: import std.stdio, sslot.signal; class Button { this() { onClick = new Signal!(); } Signal!() onClick; } class Receiver : ISlotTracking { void handleClick() { writefln("button clicked"); } mixin SlotTracking; } Button button = new Button; Receiver receiver = new Receiver; button.onClick.connect(&receiver.handleClick, receiver); button.onClick(); // prints 'button clicked' Signal!(int,int) signal = new Signal!(int,int); signal ~= (int num) { return num * num; }; assert(signal(3) == 9);It seems like having a return value in the slot that differs from the return value on the signal results in the slot silently not getting called. I'd like to be able to have a Signal!(void,int) but be able to call a method that returns something like "int method(int var)". A signal with void return should be able to just ignore the return value. At the very least the connect attempt should fail if the slot isn't going to actually get called. Other than that it seems to work pretty well. Is there no way the Signals can be initialized automatically? It's pretty ugly to have to do a new Signal in my constructor for every signal I want to declare. Actually I was getting crashes for the first little while before I realized I had to do that. --bb
Oct 30 2006
Bill Baxter wrote: > It seems like having a return value in the slot that differs from thereturn value on the signal results in the slot silently not getting called. I'd like to be able to have a Signal!(void,int) but be able to call a method that returns something like "int method(int var)". A signal with void return should be able to just ignore the return value. At the very least the connect attempt should fail if the slot isn't going to actually get called.I simply didn't think of that, thanks. The connection should fail with a compiler message, I'll fix it. It's possible, although perhaps not very safe, to cast delegates to the type the Signal can handle: signal.connect(cast(signal.DelegateSlot)method); // for delegates signal.connect(cast(signal.FunctionSlot)&method); // for functions This could be done inside Signal with parameter type checking, I'll consider it.Other than that it seems to work pretty well.Good, thank you for this feedback, I still have to test it better.Is there no way the Signals can be initialized automatically? It's pretty ugly to have to do a new Signal in my constructor for every signal I want to declare. Actually I was getting crashes for the first little while before I realized I had to do that. --bbI would like that too, but I don't see an acceptable way to do it. A signal needs to do some things in the destructor such as notifying connected slots it does not exist anymore and freeing memory allocated on the C heap. Implementing a signal as a struct instead would require to call a deinit() function or something like that which I think is worse. One thing I was thinking about is to make the signal implementation available as a mixin too, with an explicit emit() function instead of overloaded opCall. This way you could give a class itself the signal functionality without the need for inheritance, in some cases it might be more convenient.
Oct 30 2006
On Tue, 31 Oct 2006 05:41:52 +0200, Lutger <lutger.blijdestijn gmail.com> wrote:Bill Baxter wrote:[snip]If only there were ctors & dtors for structures... Or if there were 'local object members' for classes, just like in C++. For example: class Foo { Bar m_obj; //automatically constructed & destroyed with 'Foo' };Is there no way the Signals can be initialized automatically? It's pretty ugly to have to do a new Signal in my constructor for every signal I want to declare. Actually I was getting crashes for the first little while before I realized I had to do that. --bbI would like that too, but I don't see an acceptable way to do it. A signal needs to do some things in the destructor such as notifying connected slots it does not exist anymore and freeing memory allocated on the C heap. Implementing a signal as a struct instead would require to call a deinit() function or something like that which I think is worse.
Nov 01 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Kristian schrieb am 2006-11-01:Or if there were 'local object members' for classes, just like in C++. For example: class Foo { Bar m_obj; //automatically constructed & destroyed with 'Foo' };How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.learn&artnum=5016 Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFSKq/LK5blCcjpWoRAv0VAJ4hvZtQo+wZR64qRsgqlJVs29ZsSQCfe1Dt Z9/vZzgRPHl79zJzViJIkMU= =9HhU -----END PGP SIGNATURE-----
Nov 01 2006
Thomas Kuehne wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Kristian schrieb am 2006-11-01:Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language. I'll update the thing soon with some minor improvements and then start yet another rewrite / refactoring round.Or if there were 'local object members' for classes, just like in C++. For example: class Foo { Bar m_obj; //automatically constructed & destroyed with 'Foo' };How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.learn&artnum=5016 Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFSKq/LK5blCcjpWoRAv0VAJ4hvZtQo+wZR64qRsgqlJVs29ZsSQCfe1Dt Z9/vZzgRPHl79zJzViJIkMU= =9HhU -----END PGP SIGNATURE-----
Nov 01 2006
Lutger wrote:Thomas Kuehne wrote:It was added in DMD 170-172, so it hasn't been around for long. Sean-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Kristian schrieb am 2006-11-01:Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language.Or if there were 'local object members' for classes, just like in C++. For example: class Foo { Bar m_obj; //automatically constructed & destroyed with 'Foo' };How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars D.learn&artnum=5016 Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFSKq/LK5blCcjpWoRAv0VAJ4hvZtQo+wZR64qRsgqlJVs29ZsSQCfe1Dt Z9/vZzgRPHl79zJzViJIkMU= =9HhU -----END PGP SIGNATURE-----
Nov 01 2006
Sean Kelly wrote:Lutger wrote:It was added to support signals and slots, which will be in the next update. The whole thing then becomes almost trivial (!)Thomas Kuehne wrote:It was added in DMD 170-172, so it hasn't been around for long.How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars D.learn&artnum=5016Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language.
Nov 01 2006
Walter Bright wrote:Sean Kelly wrote:You are the man! I have been experimenting with hooking into object destruction by replacing the dtor pointer in the classinfo. I came across the monitor reference today in the ABI docs and have been looking into it - wondering what you are up to. This is Very Cool! Thanks!Lutger wrote:It was added to support signals and slots, which will be in the next update. The whole thing then becomes almost trivial (!)Thomas Kuehne wrote:It was added in DMD 170-172, so it hasn't been around for long.How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars D.learn&artnum=5016Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language.
Nov 01 2006
J Duncan wrote:You are the man! I have been experimenting with hooking into object destruction by replacing the dtor pointer in the classinfo.I looked into that, too, and decided that it was never going to work. Everything I thought of just cost too much memory and runtime for all objects, not just hooked ones.I came across the monitor reference today in the ABI docs and have been looking into it - wondering what you are up to. This is Very Cool! Thanks!I had a flash of inspiration one day that I was trying to hook in the wrong place. Since the monitor is an opaque type, that could be hooked with only a bit of casting, and it wouldn't affect anything else. Best of all, it only costs if it is used, not for the usual case. The monitors even still work with hooked objects. I didn't like having to tinker around under the hood like that, but it was in a good cause.
Nov 01 2006
Walter Bright wrote:J Duncan wrote:I agree. Ares allows object destruction in general to be hooked, but it's really more for detecting memory 'leaks' (non-deterministic destruction) and for conditionally special handling of the destruction of certain object types. While I haven't used the new hooking mechanism yet, it does seem to be the most appropriate solution for signals/slots.You are the man! I have been experimenting with hooking into object destruction by replacing the dtor pointer in the classinfo.I looked into that, too, and decided that it was never going to work. Everything I thought of just cost too much memory and runtime for all objects, not just hooked ones.Yup, this was definitely a nice way to do it. And it came with a rewrite of the monitor code to boot :-) I think the result is cleaner overall than what we had before. SeanI came across the monitor reference today in the ABI docs and have been looking into it - wondering what you are up to. This is Very Cool! Thanks!I had a flash of inspiration one day that I was trying to hook in the wrong place. Since the monitor is an opaque type, that could be hooked with only a bit of casting, and it wouldn't affect anything else. Best of all, it only costs if it is used, not for the usual case. The monitors even still work with hooked objects.
Nov 01 2006
Walter Bright wrote:Sean Kelly wrote:Now that is great! Didn't expect this so soon, I'll wait until then to see if this lib is still relevant. Some very useful features are getting into D lately, especially for library development.Lutger wrote:It was added to support signals and slots, which will be in the next update. The whole thing then becomes almost trivial (!)Thomas Kuehne wrote:It was added in DMD 170-172, so it hasn't been around for long.How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars D.learn&artnum=5016Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language.
Nov 01 2006
Walter Bright wrote:Sean Kelly wrote:Wow! Excellent. Any chance you'll run the API by the newsgroup for feedback before the actual release? --bbLutger wrote:It was added to support signals and slots, which will be in the next update. The whole thing then becomes almost trivial (!)Thomas Kuehne wrote:It was added in DMD 170-172, so it hasn't been around for long.How about Object.notifyRegister and Object.notifyUnRegister? sample use: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars D.learn&artnum=5016Oh crap I wish I knew about this undocumented feature before. Thank you this could be very useful, at least until weak references are part of the language.
Nov 01 2006
Bill Baxter wrote:Wow! Excellent. Any chance you'll run the API by the newsgroup for feedback before the actual release?I'd like to wait a bit first, I'm not ready yet.
Nov 01 2006