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