digitalmars.D - std.signals with multiple signals?
- Serg Kovrov (17/52) Nov 15 2006 Hello, D-folks!
- Bill Baxter (60/81) Nov 15 2006 In Qt-style S&S, the signal is an object that knows how to do its own
- Serg Kovrov (6/6) Nov 15 2006 Thanks for examples and explanations, Bill.
- Bill Baxter (4/10) Nov 15 2006 Yeh I missed that at first too. That was the first I learned you could
- Ary Manzana (6/12) Nov 16 2006 I missed that too the first say I saw it. Could the example in
- Serg Kovrov (6/10) Nov 16 2006 True, I did not yet implement disconnecting, mostly because my Listeners...
Hello, D-folks! First, my understanding of S&S: Instance of 'emitter' class could emit predefined set of signals. And arbitrary class could be a 'listener', e.g. connect any of those 'signals' to a it's 'slot' (arbitrary method with particular signature). And I expect something like this pseudo code: connect emitter.clicked to listener.do_something connect emitter.double_clicked to listener.do_something_else With current std.signals (http://digitalmars.com/d/phobos/std_signals.html) I don't get how to choose signal to connect to particular slot. I mean, how to define more than one signal? Meanwhile, before std.signals and all S&S buzz, I used followed (simplified, but you could see the idea) approach:class Emitter { enum EV {CLICKED, DBLCLICKED} void delegate()[EV] subscribers; void emit(EV ev) { auto fn = ev in subscribers; try { if (fn != null) (*fn)(); } catch (Exception wtf) { writefln("WTF? %s", wtf); } } void subscribe(EV ev, void delegate() fn) { subscribers[ev] = fn; } void click() { emit(EV.CLICKED); } void dblclick() { emit(EV.DBLCLICKED); } } class Listener { void do_something() { writefln("do_something"); } void do_something_else() { writefln("do_something_else"); } } void main() { auto emitter = new Emitter(); auto listener = new Listener(); emitter.subscribe(Emitter.EV.CLICKED, &listener.do_something); emitter.subscribe(Emitter.EV.DBLCLICKED, &listener.do_something_else); emitter.click(); delete listener; emitter.dblclick(); }And it quite works for me, is there something wrong with it? -- serg.
Nov 15 2006
Serg Kovrov wrote:Hello, D-folks!Howdy.First, my understanding of S&S: Instance of 'emitter' class could emit predefined set of signals.In Qt-style S&S, the signal is an object that knows how to do its own emitting, rather than just being some enum code and relying on an Emitter object. It's just a stylistic choice, but I think it's cleaner than having one emitter who knows about multiple kinds of signals.And arbitrary class could be a 'listener', e.g. connect any of those 'signals' to a it's 'slot' (arbitrary method with particular signature).That part is the same with Qt / phobos sig&slot.And I expect something like this pseudo code: connect emitter.clicked to listener.do_something connect emitter.double_clicked to listener.do_something_else With current std.signals (http://digitalmars.com/d/phobos/std_signals.html) I don't get how to choose signal to connect to particular slot. I mean, how to define more than one signal?Like this: class MyClass { mixin Signal!() clicked; mixin Signal!() dblclicked; }; ... auto c = new MyClass; c.clicked.connect(&listener.do_something); c.dblclicked.connect(&listener.do_something_else); clicked.emit(); dblclicked.emit(); Or with the signalobj.d file I posted a few messages back you can do: auto clicked = new SignalObj!(); auto dlbclicked = new SignalObj!(); clicked.connect(&listener.do_something); dblclicked.connect(&listener.do_something_else); clicked.emit(); dblclicked.emit(); SignalObj is basically nothing more than: class(T...){ mixin Signal!(T); }Meanwhile, before std.signals and all S&S buzz, I used followed (simplified, but you could see the idea) approach:One thing that's missing from your simplified S&S is that your signal can't pass any extra information to the slots/listeners. Your emitter only accepts delegates with zero arguments. You could write a different Emitter that can pass some arguments, but every time you have a different set of arguments to pass you'd have to write a new Emitter. The std.signal.Signal mixin automates all that. mixin Signal!(Widget,double) value_changed; That one line of code basically creates an entire new customized version of your Emitter class tailored for passing a Widget and a double to listeners. Another difference is that you haven't provided anything for disconnecting a listener who's no longer interested, or made any provisions for a listener getting destroyed. All that is handled by std.signals. Furthermore if you use the FlexSignal class I just posted a few messages back you will gain additional capabilities like being able to connect this function: int set_value(int v) { writefln("The value is: ", v); } to this signal: FlexSignal!(int, char[]) sig; sig.emit(5, "A message") will call set_value(5) and ignore its return value. With SignalObj, or a std.signals 'mixin Signal', trying to connect these two will give you a variety of compile time errors, because a) it's a function and not a delegate, and because b) it has a return value, and because c) it doesn't take as many arguments as the Signal was expecting. But your basic approach (make an array of delegates) is the same as what std.signals uses. --bbclass Emitter { [snip] }And it quite works for me, is there something wrong with it?
Nov 15 2006
Thanks for examples and explanations, Bill. The key point I have overlooked in docs is "Different signals can be added to a class _by naming the mixins_". That clicked everything into place. -- serg.
Nov 15 2006
Serg Kovrov wrote:Thanks for examples and explanations, Bill. The key point I have overlooked in docs is "Different signals can be added to a class _by naming the mixins_". That clicked everything into place.Yeh I missed that at first too. That was the first I learned you could name a mixin, too. :-) --bb
Nov 15 2006
Serg Kovrov escribió:Thanks for examples and explanations, Bill. The key point I have overlooked in docs is "Different signals can be added to a class _by naming the mixins_". That clicked everything into place.I missed that too the first say I saw it. Could the example in http://www.digitalmars.com/d/phobos/std_signals.html be changed to use named signals, and more than one in a class? Thanks, Ary
Nov 16 2006
Bill Baxter wrote:Another difference is that you haven't provided anything for disconnecting a listener who's no longer interested, or made any provisions for a listener getting destroyed. All that is handled by std.signals.True, I did not yet implement disconnecting, mostly because my Listeners usually lives longer than Subjects. In those rare cases I just catch an "Access Violation" exception, which probably not a best practice, though. -- serg.
Nov 16 2006