Multiple delegates, contextual delegates
Aphex
Aphex at mail.com
Mon Jun 24 16:05:33 UTC 2019
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?
More information about the Digitalmars-d
mailing list