Multiple delegates, contextual delegates
angel
andrey.gelman at gmail.com
Wed Jun 26 09:48:35 UTC 2019
On Monday, 24 June 2019 at 16:05:33 UTC, Aphex wrote:
> I believe it would really help D to have multiple delegates and
> contextual delegates.
>
> Take, for example
>
> alias Caller = void delegate();
>
> class X
> {
> Caller Do;
> }
>
>
> x.Do = () { };
>
>
> The issue is that one cannot assign multiple functions to Do
> and easily call them all in sequence(or even parallel using
> tasks).
>
> I have created a library solution but the problem is that I
> have to keep the library around. I believe it is a very useful
> tool to be able to contain multiple delegates in a single
> object reference because there are many applications where one
> wants too allow multiple behaviors attached to a single
> reference. E.g., it has applications in messaging,
> notifications, graphics, systems, etc.
>
> It's true one can simply make an array of callbacks, but then
> one still has to manually fire them all, deal with nulls, etc.
>
>
> Ideally something like
>
> alias Caller = void mdelegate();
>
> class X
> {
> Caller Do;
> }
>
> x.Do = () { writeln("1"); };
>
> x.Do = () { writeln("2"); };
>
> x.Do = () { writeln("3"); };
>
> x.Do();
>
> then fires all the delegates(in sequence of course). (One
> could use ~= or += for adding and -= for removing if one wants)
>
> It is true that this can somewhat be effectively done in a
> library but it should be part of the standard library and
> implemented well. I think though that it is better part of the
> language itself because it is quite useful.
>
> One could have different ways to fire the delegate such as
> sequential iterative(sorta emulating yield) or parallel(creates
> a task for each one).
>
> By having mdelegate one can immediately convert a delegate in
> to a mutlidelegate by a search and replace of the term without
> any issues or modification of other code, except if = is used
> which might cause problems on reassignment. It may require
> slight modifications on assignment to make things work but a
> mdelegate can behave as a normal delegate otherwise.
>
>
> Contextual delegates are simply delegates that are methods that
> also capture the context.
>
>
>
>
> alias Caller = void cdelegate();
>
> class X
> {
> int z = 3;
> Caller Do;
> }
>
> int z = 4;
> int y = 10;
> x.Do = () { writeln(context.z*y); }; // context used to
> disambiguate and reference object(possibly could use this but a
> this may already exist)
>
> x.Do();
>
>
> Essentially it keeps two "this"'es. The this of the object also
> of the context.
>
> It's true one can do this as
>
>
> alias Caller = void cdelegate(X);
>
> class X
> {
> int z = 3;
> Caller Do;
> }
>
> int y = 10;
> x.Do = (q) { writeln(q.z*y); };
>
> x.Do(x);
>
> It might be better called member delegates as they are hybrids
> of members and delegates.
>
>
> While it doesn't seem like much work to create them in d, it is
> quite ugly in having to pass the object.
>
>
> By having a cdelegate one immediately can convert delegates
> used in structs and classes in to more powerful objects with no
> other code change than a search and replace. Without it one has
> to find all occurrence of and modify it to work.
>
>
>
> Of course, then one has cmdelegate! ;) A contextual multi
> delegate! Isn't generalization fun?
>
> These features really take very little compiler magic. Multi
> delegates can be done in a library but contextual delegates
> cannot. Both extend delegates very easily and without much
> trouble yet make them more powerful. They also can be combined
> to multiply the usefulness.
>
> In fact, it may be possible to simply extend the above behavior
> to the keyword delegate without any ill-effect. It would be
> 100% backwards compatible. The only issue is dealing with the
> assignment of delegates since previous behavior is expected to
> overwrite while new behavior would be expected to append... and
> these are mutually exclusive. To keep things 100% backwards
> compatible would require assignment to overwrite which would
> turn a multi-delegate in to a single delegate... and appendage
> would turn a delegate in to a multi-delegate.
>
> e.g.,
>
> x.Do = () { }; // First, and so old school delegate.
> x.Do = () { }; // Overwrites.
> x.Do += () { }; // Added a new delegate and now we have a
> multi-delegate with 2 delegates
>
> x.Do = () { }; // Back to a single delegate that overwrote the
> previous two.
> x.Do += () { }; // Added a new delegate and now we have a
> multi-delegate with 2 delegates
> x.Do -= () { }; // Back to a single delegate since we removed
> the old one(technically not since the reference must be correct)
>
>
> So the only issue here is that using multi-delegates in
> pre-existing code may fail if one does not know about future
> assignment and the multi-delegates get overwritten. This
> generally won't be a problem because rarely does one assign to
> a delegate multiple times, but even so, it's just a matter of
> converting to the appender op.
>
> The power these offer far outweigh the rare likelihood of
> unexpected behavior(one far more likely to have other more
> serious issues such as a typical buffer overflow).
>
>
>
> What do you think?
Indeed it looks like a library solution.
Its alleged usefulness has nothing to do with being a library as
opposed to being a part of the core language. Normally, the core
language implements stuff that is very hard or very ugly to
implement in a library, and your proposal will look perfect in a
library implementation.
Another question regarding the "-=" operator - a delegate removal.
How can you recognize the delegate that has to be removed ? Do
you need to type in the delegate code, just to identify the
candidate for removal ?
More information about the Digitalmars-d
mailing list