www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How would you implement this in D? (signals & slots)

reply Enjoys Math <enjoysmath gmail.com> writes:
module signals_and_slots;

import std.algorithm: remove;

struct Slots(DelegateType, ArgTypes...) {
	this() {

	}

	// How would you implement this?
	void call(ArgTypes args) {
		foreach (dg; delegates)
			dg(args);
	}

	void connect(DelegateType slot) {
		foreach (dg; delegates) {
			if (dg == slot)
				return;
		}
		delegates ~= slot;
	}

	void disconnect(DelegateType slot) {
		for (uint k=0; k < delegates.length; k++) {
			if (delegates[k] == slot)
				delegates = delegates.remove(k);
		}
	}

private:
	DelegateType[] delegates;
}

=============================================================

How do you implement this template called like:
void onColorChange(in Color) {
    // do something with color
}
auto slots = Slots!(void delegate(in Color), Color);
slots.connect(&onColorChange);
auto color = Color(0.0, 1.0, 1.0, 1.0);
slots.call(color);

?

Thank you!
Feb 01 2016
next sibling parent reply Enjoys Math <enjoysmath gmail.com> writes:
On Monday, 1 February 2016 at 21:40:45 UTC, Enjoys Math wrote:
 module signals_and_slots;

 import std.algorithm: remove;

 [...]
D's signals & slots: https://dlang.org/phobos/std_signals.html
Feb 01 2016
parent reply Gerald <me me.com> writes:
On Monday, 1 February 2016 at 21:44:28 UTC, Enjoys Math wrote:
 On Monday, 1 February 2016 at 21:40:45 UTC, Enjoys Math wrote:
 module signals_and_slots;

 import std.algorithm: remove;

 [...]
D's signals & slots: https://dlang.org/phobos/std_signals.html
I looked at that and perhaps I'm not reading the exampes correctly but I'm not sure how useful std.signals is in the real world. If you have a bunch of slots which take the same parameter types, not unusual in the GUI world, how would that work? The other thing that bugs me is lack of naming for slots and signals, again in the GUI world where you typically have dozens of these on an an individual widget differentiation is quite important. For my GtkD app where I need my own events between components outside of the built-in GTK ones I've just been rolling my own by hand using delegates similar to your example. It's pretty trivial but admittingly there is a bunch of boilerplate I'd love to eliminate via templates if there is a way to address the weaknesses with std.signals.
Feb 02 2016
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 2 February 2016 at 14:49:21 UTC, Gerald wrote:
 On Monday, 1 February 2016 at 21:44:28 UTC, Enjoys Math wrote:
 On Monday, 1 February 2016 at 21:40:45 UTC, Enjoys Math wrote:
 module signals_and_slots;

 import std.algorithm: remove;

 [...]
D's signals & slots: https://dlang.org/phobos/std_signals.html
I looked at that and perhaps I'm not reading the exampes correctly but I'm not sure how useful std.signals is in the real world. If you have a bunch of slots which take the same parameter types, not unusual in the GUI world, how would that work?
Switch on the value inside the slot. Or use different types by wrapping, say, an int or a string with a struct: import std.stdio; import std.signals; struct String1 { string s; } struct String2 { string s; } class Observer { void watch1(String1) { writeln("watch1"); } void watch2(String2) { writeln("watch2"); } } class Signals { mixin Signal!String1; mixin Signal!String2; } void main() { auto o = new Observer; auto s = new Signals; s.connect(&o.watch1); s.connect(&o.watch2); s.emit(String1("foo")); s.emit(String2("bar")); }
 The other thing that bugs me is lack of naming for slots and 
 signals, again in the GUI world where you typically have dozens 
 of these on an an individual widget differentiation is quite 
 important.
Slots are named: the methods are slots. Signals can be named if you use only one struct as the parameter, as above. The signals would be String1 and String2, the slots watch1 and watch2. Atila
Feb 02 2016
next sibling parent Kagamin <spam here.lot> writes:
http://dpaste.dzfl.pl/f888feb6f743
Feb 02 2016
prev sibling next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Tue, 02 Feb 2016 15:59:06 +0000, Atila Neves wrote:
 struct String1 { string s; }
 struct String2 { string s; }
I've seen this sort of thing before. A blogger I used to follow, Jeremy Miller, implemented an event broker using this pattern. I don't like it. It requires a new type for each event, and you have to defensively use that pattern even if you only have one event at the moment. Every time I implemented an event system, I've gone with named events and no special type for their parameters. With std.signals, you could do this: struct Event(TArgs...) { mixin Signal!TArgs; } class Foo { Event!string usernameEntered; Event!string passwordEntered; Event!(long, string) someOtherEventHappened; void enterPassword(string s) { passwordEntered.emit(s); } void enterUsername(string s) { usernameEntered.emit(s); } } void main() { auto o = new Observer; auto f = new Foo; f.usernameEntered.connect(&o.watch); f.passwordEntered.connect(&o.watch); f.enterUsername("adelhurst"); f.enterPassword("********"); }
Feb 02 2016
parent Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 2 February 2016 at 17:35:25 UTC, Chris Wright wrote:
 On Tue, 02 Feb 2016 15:59:06 +0000, Atila Neves wrote:
 [...]
I've seen this sort of thing before. A blogger I used to follow, Jeremy Miller, implemented an event broker using this pattern. I don't like it. It requires a new type for each event, and you have to defensively use that pattern even if you only have one event at the moment. Every time I implemented an event system, I've gone with named events and no special type for their parameters. [...]
Nice. I liked your example and Kagamin's better than mine. Atila
Feb 02 2016
prev sibling parent Gerald <me me.com> writes:
On Tuesday, 2 February 2016 at 15:59:06 UTC, Atila Neves wrote:
 Slots are named: the methods are slots. Signals can be named if 
 you use only one struct as the parameter, as above. The signals 
 would be String1 and String2, the slots watch1 and watch2.
What I meant is that the connect call didn't seem to tie you to a specific slot, it looked like it determined the slot based on the types which is potentially error prone. Kagamin showed an example of explicitly connecting to a named slot so I'm happy with that, I'm looking forward to re-writing my event handlers using this technique. Always nice to learn something new.
Feb 02 2016
prev sibling parent Vadim Lopatin <coolreader.org gmail.com> writes:
On Monday, 1 February 2016 at 21:40:45 UTC, Enjoys Math wrote:
 module signals_and_slots;
 How do you implement this template called like:
 void onColorChange(in Color) {
    // do something with color
 }
 auto slots = Slots!(void delegate(in Color), Color);
 slots.connect(&onColorChange);
 auto color = Color(0.0, 1.0, 1.0, 1.0);
 slots.call(color);
Signals in DlangUI: https://github.com/buggins/dlangui/blob/master/src/dlangui/core/signals.d
Feb 03 2016