std.signals2 proposal

Zhenya zheny at list.ru
Mon Nov 5 10:40:30 PST 2012


On Monday, 5 November 2012 at 13:35:26 UTC, Robert wrote:
> Hi there!
>
> I just developed a proof-of-concept implementation of an 
> improved
> std.signals.
>
> Things I did not like about the current implementation:
>
> 1. Passing a delegate to connect, which basically is an 
> extended (void*)
> and assuming it is an object delegate, does not feel quite 
> right in D,
> where we usually try to guarantee correctness by the compiler 
> wherever
> possible.
>
> 2. The restriction that only objects can be connected.
>
> Point 2 does not really bother me, because from my little 
> experience I
> never really had connected anything else than objects to a 
> signal. But
> the restriction that the connected delegate must not be some 
> wrapper, is
> quite a restriction I came to dislike about Qt and even more so 
> with
> this implementation because unlike Qt the signatures have to 
> match
> exactly, you can't omit parameters, like:
> // Qt code
> connect(button, SIGNAL(clicked(bool)), this, 
> SLOT(buttonClicked());
>
> -> In the current implementation buttonClicked would have to 
> take a
> bool.
>
> In addition boost::signals together with boost::bind offered 
> even more
> comfort like passing additional parameters to a slot, which is 
> really
> very, very useful:
>
> for(int i=0; i<buttons.length(); i++) {
> 	buttons[i].clicked.connect(boost::bind(&MyObj::addNumber, this,
>  i));
> }
>
> So I tried to improve std.signals, code:
> (warning at least one bug is remaining, explained below)
>
> https://github.com/eskimor/phobos/tree/new_signal
>
> You can easily connect to an object's method with:
>
> obj.signal.connect!"someMethod"(obj);
>
> instead of the old implementation:
>
> obj.signal.connect(&obj.someMethod);
>
> -> The interface is clean and type safe, all the ugly details 
> are hidden
> from the user. And it is just one character more typing. Simple 
> things
> stay simple.
>
> In addition a method allowing wrapper delegates was added:
>
> class Observer {
> 	void addNumber(int i) {
> 		sum+=i;
> 	}
> 	int sum;
> }
>
> class Button {
> 	Signal!(bool) clicked;
> 	// ...
> }
>
> void main() {
> 	auto b=new Button;
> 	auto o=new Observer;
> 	// Ignore boolean parameter and pass some int:
> 	b.connect!Observer(o, (o, p) { o.addNumber(7); });
> 	// or even:
> 	b.connect!Observer(o, (o, p) => o.addNumber(7));
> 	// For some reason the compiler is not able to deduce "o" being
> 	// Observer, so the !Observer is needed, but it is still very
> 	// neat and readable.
> }
>
> Thanks to D's lamdas the syntax is even more concise as 
> boost::bind and
> far more powerful.
>
> By passing the object explicitly to the delegate, it is 
> possible to
> maintain the 'weak ref' semantics to the target object, while 
> ensuring
> that the delegates context won't be freed.
>
> As a side effect it is now even possible to use struct 
> delegates or even
> any non object delegate. Simply pass null for the obj 
> parameter. It is
> completely safe, the only drawback is that the struct won't be 
> deleted
> until the Button gets destroyed. (Because it holds a reference 
> to the
> struct, by means of the delegate.) But for long lived structs 
> this
> usually is perfectly acceptable.
>
> Implementation:
>
> In my implementation I changed the Signal mixin to be a simple 
> template
> struct, because I hit strange compiler errors with it being a 
> mixin. The
> most prominent:
>
> std/signals.d(443): Error: no overload matches for 
> connect(string
> method,T2) if (is(T2 : Object))
>
> You can find the version triggering these errors at:
>
> https://github.com/eskimor/phobos/tree/new_signal_mixin
>
> Also I did not really get the point why a mixin was used in the 
> first
> place, it does not really gain us anything? What was the 
> reasoning about
> it?
> I almost thought I found the reason, because my implementations 
> suffers
> from unhook not being called, although it was properly 
> registered with
> "rt_attachDisposeEvent(obj, &unhook);", thus causing a 
> segmentation
> fault when the observer gets deleted. I did not really find any
> difference from the original version that could explain this 
> behavior,
> despite the original implementation being a mixin. So I 
> thought, well
> maybe the delegate passed to "rt_attachDisposeEvent(obj, 
> &unhook);" must
> be an object delegate (that's would be why the mixin was 
> needed), but
> after digging in object_.d I did not find any code assuming 
> that the
> delegate was an object delegate. Any ideas on this?
>
> Another thing I'd like to ask Walter, is what the "L1:" label 
> is for in
> connect(), is it just some left over or has it some special 
> internal
> compiler thing meaning?
>
> What do you think?
>
> Best regards,
>
> Robert

Hi!Could you write some examples for struct and non-object 
delegates?



More information about the Digitalmars-d mailing list