www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Two part question. Making a dynamic array of delegates, and taking in

reply Payotz <payotz530 gmail.com> writes:
So, to give context, I am trying to make an event manager for a 
game I'm making.
I was writing the "register()" method so I ran into a problem.

The register method will take in delegates as an argument, but 
those delegates have varied arguments themselves, so I can't 
really put anything there. I know that it's got something to do 
with templates so I tried my hand in it and came up with this:

void registerEvent(string event_name,T...)(T delegate() dg);

I know there's something missing in the way I did it, so I'll be 
glad for you folks to tell me what I'm missing.

And for the second part of the question, I can't seem to make a 
Dynamic Array where I could store the delegates taken in the 
"registerEvent" method. Closest thing I have gotten to is this:

private void delegate(T)(T args)[string] event;

which resulted in the compiler screaming Error signs at me.
So how does one do it?
Dec 01 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/01/2016 03:51 PM, Payotz wrote:
 So, to give context, I am trying to make an event manager for a game I'm
 making.
 I was writing the "register()" method so I ran into a problem.

 The register method will take in delegates as an argument, but those
 delegates have varied arguments themselves, so I can't really put
 anything there.
What you know is how you will call them. Let's assume just an int argument.
 I know that it's got something to do with templates so I
 tried my hand in it and came up with this:

 void registerEvent(string event_name,T...)(T delegate() dg);
Binding state to callables is pretty easy in D. You don't want to pass the arguments to the registration because it wouldn't know what to do with those: Store the state for the delegate? Maybe, maybe not.
 I know there's something missing in the way I did it, so I'll be glad
 for you folks to tell me what I'm missing.
All you need is your interface to these callbacks.
 And for the second part of the question, I can't seem to make a Dynamic
 Array where I could store the delegates taken in the "registerEvent"
 method. Closest thing I have gotten to is this:

 private void delegate(T)(T args)[string] event;

 which resulted in the compiler screaming Error signs at me.
 So how does one do it?
Here is a start: import std.stdio; alias Func = void delegate(int); Func[string] registry; void register(string event_name, Func func) { registry[event_name] = func; } struct S { double d; string s; void foo(int i) { writefln("S.foo called with %s; my state: %s", i, this); } } void bar(int i) { writefln("bar called with %s", i); } void main() { register("trivial", (int a) => writefln("called with %s", a)); auto s = S(2.5, "hello"); register("with_struct", &s.foo); int j; register("using_local_state", (int a) { ++j; writefln("Incremented local j: %s", j); }); // This won't work as &bar because &bar is not a delegate, but a function. // Very simple with toDelegate. // http://dlang.org/phobos/std_functional.html#toDelegate import std.functional: toDelegate; register("regular_function", toDelegate(&bar)); foreach (event_name, func; registry) { writefln("--- Calling function registered for %s", event_name); func(cast(int)event_name.length); } } Ali
Dec 01 2016
prev sibling next sibling parent crimaniak <crimaniak gmail.com> writes:
On Thursday, 1 December 2016 at 23:51:19 UTC, Payotz wrote:
 So, to give context, I am trying to make an event manager for a 
 game I'm making.
 I was writing the "register()" method so I ran into a problem.

 The register method will take in delegates as an argument, but 
 those delegates have varied arguments themselves, so I can't 
 really put anything there. I know that it's got something to do 
 with templates so I tried my hand in it and came up with this:

 void registerEvent(string event_name,T...)(T delegate() dg);
May be std.variant will help you. https://dlang.org/phobos/std_variant.html You can bring the delegates to a common interface, hiding the differences in std.variant
Dec 01 2016
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Thu, Dec 01, 2016 at 11:51:19PM +0000, Payotz via Digitalmars-d-learn wrote:
 So, to give context, I am trying to make an event manager for a game
 I'm making.
 I was writing the "register()" method so I ran into a problem.
 
 The register method will take in delegates as an argument, but those
 delegates have varied arguments themselves, so I can't really put
 anything there. I know that it's got something to do with templates so
 I tried my hand in it and came up with this:
 
 void registerEvent(string event_name,T...)(T delegate() dg);
 
 I know there's something missing in the way I did it, so I'll be glad
 for you folks to tell me what I'm missing.
 
 And for the second part of the question, I can't seem to make a
 Dynamic Array where I could store the delegates taken in the
 "registerEvent" method.  Closest thing I have gotten to is this:
 
 private void delegate(T)(T args)[string] event;
 
 which resulted in the compiler screaming Error signs at me.
 So how does one do it?
This requires heavy trickery, because what you're essentially doing is taking a compile-time construct (type-safe variadic functions) and applying it at runtime (array elements don't know how many arguments they will have until actually initialized at runtime). The solution is non-obvious, but, thankfully, *possible*, 'cos D is just *that* awesome. ;-) An example of how to do this can be found in Adam Ruppe's eventloop.d module, available here: https://github.com/adamdruppe/arsd/blob/master/eventloop.d In particular, look at the `typehash` template, the addListener() and send() functions, and the WrappedListener interface (along with the wrap() function). That should give you the basic idea of what's involved. Past that, there are also some dirty implementation details you have to work with such as getPtrPair() that performs some compiler-dependent type-casting black magic just to tie things together. (Alternatively, you could just use eventloop.d in your game and save yourself the trouble of reinventing it yourself. ;-) It has a pretty nice API that I've used in my own projects quite successfuly.) T -- Shin: (n.) A device for finding furniture in the dark.
Dec 01 2016
prev sibling next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 1 December 2016 at 23:51:19 UTC, Payotz wrote:
 So, to give context, I am trying to make an event manager for a 
 game I'm making.
 I was writing the "register()" method so I ran into a problem.

 The register method will take in delegates as an argument, but 
 those delegates have varied arguments themselves, so I can't 
 really put anything there. I know that it's got something to do 
 with templates so I tried my hand in it and came up with this:

 void registerEvent(string event_name,T...)(T delegate() dg);
You could do what pthread does in C to achieve similar goals. void delegate(void*); // or int delegate(void*) if you want to return an error code and then store the void pointer along with the delegate and then cast the void* to the correct type (a struct of arguments or similar) and call it later. not very safe but there are ways to make it nicer. However if the set of types of events is closed you can use ailas event = Algebraic!(ev1,ev2,ev3...); where ev1 and so on are structs that hold parameters of the event. and have void delegate(event); This is effectively how SDL does events.
 I know there's something missing in the way I did it, so I'll 
 be glad for you folks to tell me what I'm missing.

 And for the second part of the question, I can't seem to make a 
 Dynamic Array where I could store the delegates taken in the 
 "registerEvent" method. Closest thing I have gotten to is this:

 private void delegate(T)(T args)[string] event;

 which resulted in the compiler screaming Error signs at me.
 So how does one do it?
You get an error here because you are trying to have an associative array of templates. if they were all void delegate(int)'s that would work. You can't use an uninstantiated template as a type.
Dec 01 2016
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 1 December 2016 at 23:51:19 UTC, Payotz wrote:

 The register method will take in delegates as an argument, but 
 those delegates have varied arguments themselves, so I can't 
 really put anything there. I know that it's got something to do 
 with templates so I tried my hand in it and came up with this:

 void registerEvent(string event_name,T...)(T delegate() dg);
Off the top of my head, you should be able to do something like this: void registerEvent(string event_name, T, Args...)(T delegate(Args) dg) {}
 I know there's something missing in the way I did it, so I'll 
 be glad for you folks to tell me what I'm missing.

 And for the second part of the question, I can't seem to make a 
 Dynamic Array where I could store the delegates taken in the 
 "registerEvent" method. Closest thing I have gotten to is this:

 private void delegate(T)(T args)[string] event;

 which resulted in the compiler screaming Error signs at me.
 So how does one do it?
This isn't going to work because you can't have an array of mixed types. Something like `KyeEvent delegate() dg` and `MouseEvent delegate() dg` are distinct types, so they can't be stored in the same array. Since you say the delegates have different parameters, the only option I'm aware of to store them is to use either the Variant or Algebraic type in std.variant. If only the return type differed, there would be other options. And I don't know what you're doing with that event_name template parameter. But anyway, checkout std.variant.
Dec 01 2016
parent Payotz <payotz530 gmail.com> writes:
Thank you all for the replies. I'm extremely grateful. I'll look 
into each and every answer.
Dec 01 2016