digitalmars.D.learn - Dispatching from receive to a function
- Bob Cowdery (17/17) Sep 27 2010 I've been looking for a way to hook up messages to a thread with a
- Johannes Pfau (20/27) Sep 27 2010 Not sure about the other questions, but here's an example for a
- Bob Cowdery (6/30) Sep 27 2010 Thanks. Do you know if the signature is a mandatory part. If I left the
- Johannes Pfau (72/77) Sep 27 2010 Yep, the signature is mandatory. There is another, ugly, unsafe (it's
- Juanjo Alvarez (40/131) Sep 27 2010 I'm new to the language so I don't know if this is horribly wrong on som...
- Johannes Pfau (8/54) Sep 27 2010 I totally forgot about Variant!
- Juanjo Alvarez (7/59) Sep 27 2010 Yep, variants are cool. You could even use an struct as value type of th...
- Bob Cowdery (25/84) Sep 27 2010 Thanks for the suggestions. I'm still hankering after an elegant
- Philippe Sigaud (8/16) Sep 27 2010 I think I got this one too. IIRC, it's a bug in the holder["test"] part ...
I've been looking for a way to hook up messages to a thread with a handler function. As far as I can tell receive pattern matching only allows the pattern to be distinguished by the parameter signature which does not help when all the handlers only have a few different signatures. I like the pattern matching concept as I have worked with Erlang which will pattern match to a term (basically an arbitrary structure). Erlang defines an Atom type which is really a global constant that can be used as a message type in the match. Does anyone know of a way to simulate this? Failing that I think a dispatcher structure using an associative array would be my next choice. However I'm getting stuck on how to define and use an array which maps a string key to a delegate. Can someone help me out there please. I will then effectively have my 'Atom' as a string in the message and dispatch on that. I don't want to hard code in a switch statement. Any other suggestions are very welcome. Thanks Bob
Sep 27 2010
On 27.09.2010 15:07, Bob Cowdery wrote:Failing that I think a dispatcher structure using an associative array would be my next choice. However I'm getting stuck on how to define and use an array which maps a string key to a delegate. Can someone help me out there please. I will then effectively have my 'Atom' as a string in the message and dispatch on that.Not sure about the other questions, but here's an example for a string/delegate associative array: ------------------------------------------- import std.stdio; alias bool delegate(int, char) TestDelegate; TestDelegate[string] dict; class C { bool test(int i, char c) {return true;} } void main() { C c = new C(); dict["test"] = &c.test; writeln(dict["test"](0, 'c')); } ----------------------------------------------- -- Johannes Pfau
Sep 27 2010
Thanks. Do you know if the signature is a mandatory part. If I left the signature out would it then only work with a delegate with no parameters? If so I think I'm in the same state as my delegates will not all have the same signature. Bob On 27/09/2010 14:21, Johannes Pfau wrote:On 27.09.2010 15:07, Bob Cowdery wrote:Failing that I think a dispatcher structure using an associative array would be my next choice. However I'm getting stuck on how to define and use an array which maps a string key to a delegate. Can someone help me out there please. I will then effectively have my 'Atom' as a string in the message and dispatch on that.Not sure about the other questions, but here's an example for a string/delegate associative array: ------------------------------------------- import std.stdio; alias bool delegate(int, char) TestDelegate; TestDelegate[string] dict; class C { bool test(int i, char c) {return true;} } void main() { C c = new C(); dict["test"] = &c.test; writeln(dict["test"](0, 'c')); } -----------------------------------------------
Sep 27 2010
On 27.09.2010 15:36, Bob Cowdery wrote:Thanks. Do you know if the signature is a mandatory part. If I left the signature out would it then only work with a delegate with no parameters? If so I think I'm in the same state as my delegates will not all have the same signature.Yep, the signature is mandatory. There is another, ugly, unsafe (it's safe, but you really have to be careful and write correct code) way: Basically you cast away the delegates type information. You then store the delegate in an array. Later, you have to cast the delegate back to it's original type. The problem here is, that D doesn't provide enough runtime type information to know which type the delegate originally had, so _we_ have to store some type info _manually_. This can for example be done by storing both the delegate and our type info in a struct. Here's an example how to do exactly that. !!!Note: It's very important to always cast the delegate back to the _correct_ type before calling it, everything else leads to undefined behavior!!! So just setting CDelegate.Type to a wrong type can cause a disaster! (Sorry about the bad variable names in the example. For better encapsulation most of the casts could be moved into the CDelegate struct by adding functions and constructors) --------------------------------------------------------------------------- import std.stdio; enum DelegateType { A, B, C, D } struct CDelegate { void delegate() del; //Exact type doesn't matter, all delegates have the same size DelegateType Type; } CDelegate[string] dict; class C { bool test(int i, char c) {return true;} } class D { int test(string s) {return 99;} } void main() { C c = new C(); D d = new D(); CDelegate custom; custom.del = cast(void delegate())&c.test; custom.Type = DelegateType.C; dict["c"] = custom; custom.del = cast(void delegate())&d.test; custom.Type = DelegateType.D; dict["d"] = custom; foreach(cdeleg; dict) { switch(cdeleg.Type) { case DelegateType.C: bool delegate(int i, char c) realdel = cast (bool delegate(int i, char c)) cdeleg.del; writeln(realdel(0, 'c')); break; case DelegateType.D: int delegate(string) realdel = cast (int delegate(string)) cdeleg.del; writeln(realdel("test")); break; } } } --------------------------------------------------------------------------- -- Johannes Pfau
Sep 27 2010
I'm new to the language so I don't know if this is horribly wrong on some levels, but it works: ----------------------------- import std.variant; import std.stdio; class C { bool test(int i, char c) { writeln("Hello from test1"); return true; } void test2(string v) { writeln("Hello from test2, ", v); } } void main() { auto c = new C; Variant[string] holder = ["test": Variant(&c.test), "test2": Variant (&c.test2)]; receiver(holder); } void receiver(Variant[string] message) { // If you get the Variant template instantiation delegate // signature wrong, it will // be detected at compile time! auto t = message["test"].get!(bool delegate(int, char)); auto t2 = message["test2"].get!(void delegate(string)); t(1, 'c'); t2("foo"); } -------------------------- Curiously if you create holder like this, it will give an arrayoutofbound error at runtime, I don't know if that is a bug: void main() { auto c = new C; Variant[string] holder; holder["test"] = Variant(&c.test); holder["test2"] = Variant(&c.test2); } On Mon, 27 Sep 2010 18:03:32 +0200, Johannes Pfau wrote:On 27.09.2010 15:36, Bob Cowdery wrote:---------------------------------------------------------------------------Thanks. Do you know if the signature is a mandatory part. If I left the signature out would it then only work with a delegate with no parameters? If so I think I'm in the same state as my delegates will not all have the same signature.Yep, the signature is mandatory. There is another, ugly, unsafe (it's safe, but you really have to be careful and write correct code) way: Basically you cast away the delegates type information. You then store the delegate in an array. Later, you have to cast the delegate back to it's original type. The problem here is, that D doesn't provide enough runtime type information to know which type the delegate originally had, so _we_ have to store some type info _manually_. This can for example be done by storing both the delegate and our type info in a struct. Here's an example how to do exactly that. !!!Note: It's very important to always cast the delegate back to the _correct_ type before calling it, everything else leads to undefined behavior!!! So just setting CDelegate.Type to a wrong type can cause a disaster! (Sorry about the bad variable names in the example. For better encapsulation most of the casts could be moved into the CDelegate struct by adding functions and constructors)import std.stdio; enum DelegateType { A, B, C, D } struct CDelegate { void delegate() del; //Exact type doesn't matter, all delegates have the same size DelegateType Type; } CDelegate[string] dict; class C { bool test(int i, char c) {return true;} } class D { int test(string s) {return 99;} } void main() { C c = new C(); D d = new D(); CDelegate custom; custom.del = cast(void delegate())&c.test; custom.Type = DelegateType.C; dict["c"] = custom; custom.del = cast(void delegate())&d.test; custom.Type = DelegateType.D; dict["d"] = custom; foreach(cdeleg; dict) { switch(cdeleg.Type) { case DelegateType.C: bool delegate(int i, char c) realdel = cast (bool delegate(int i, char c)) cdeleg.del; writeln(realdel(0, 'c')); break; case DelegateType.D: int delegate(string) realdel = cast (int delegate(string)) cdeleg.del; writeln(realdel("test")); break; } } }---------------------------------------------------------------------------
Sep 27 2010
On 27.09.2010 20:46, Juanjo Alvarez wrote:I'm new to the language so I don't know if this is horribly wrong on some levels, but it works: ----------------------------- import std.variant; import std.stdio; class C { bool test(int i, char c) { writeln("Hello from test1"); return true; } void test2(string v) { writeln("Hello from test2, ", v); } } void main() { auto c = new C; Variant[string] holder = ["test": Variant(&c.test), "test2": Variant (&c.test2)]; receiver(holder); } void receiver(Variant[string] message) { // If you get the Variant template instantiation delegate // signature wrong, it will // be detected at compile time! auto t = message["test"].get!(bool delegate(int, char)); auto t2 = message["test2"].get!(void delegate(string)); t(1, 'c'); t2("foo"); } -------------------------- Curiously if you create holder like this, it will give an arrayoutofbound error at runtime, I don't know if that is a bug: void main() { auto c = new C; Variant[string] holder; holder["test"] = Variant(&c.test); holder["test2"] = Variant(&c.test2); }I totally forgot about Variant! As far as I know that's exactly what variant is for and it's way better than my proposed hack. The example you posted is perfectly fine as well. I'm not sure what causes the arrayoutofbound error, the second example is correct as well. -- Johannes Pfau
Sep 27 2010
On Mon, 27 Sep 2010 21:00:48 +0200, Johannes Pfau wrote:On 27.09.2010 20:46, Juanjo Alvarez wrote:Yep, variants are cool. You could even use an struct as value type of the associative array and store the variant in one member and the signature of the delegate, as string, in another member. The you could use a mixin in the receiver to extract the delegate without knowing the original signature. All this is wonderfully disturbing to me :)I'm new to the language so I don't know if this is horribly wrong on some levels, but it works: ----------------------------- import std.variant; import std.stdio; class C { bool test(int i, char c) { writeln("Hello from test1"); return true; } void test2(string v) { writeln("Hello from test2, ", v); } } void main() { auto c = new C; Variant[string] holder = ["test": Variant(&c.test), "test2": Variant (&c.test2)]; receiver(holder); } void receiver(Variant[string] message) { // If you get the Variant template instantiation delegate // signature wrong, it will // be detected at compile time! auto t = message["test"].get!(bool delegate(int, char)); auto t2 = message["test2"].get!(void delegate(string)); t(1, 'c'); t2("foo"); } -------------------------- Curiously if you create holder like this, it will give an arrayoutofbound error at runtime, I don't know if that is a bug: void main() { auto c = new C; Variant[string] holder; holder["test"] = Variant(&c.test); holder["test2"] = Variant(&c.test2); }I totally forgot about Variant! As far as I know that's exactly what variant is for and it's way better than my proposed hack. The example you posted is perfectly fine as well. I'm not sure what causes the arrayoutofbound error, the second example is correct as well.
Sep 27 2010
Thanks for the suggestions. I'm still hankering after an elegant solution to the receive rather than try to patch it up after the event. The best I can come up with is pretty ugly (odd) at the front but looks better at the back-end. Maybe someone can refine it a bit. struct RATE{}; struct SRC_1{}; struct SRC_2{}; class OutputFrame{ void set_rate(RATE desc, int speed) {..} void set_clock_src1(SRC_1 desc, string lo_ref){...} void set_clock_src2(SRC_2 desc, string hi_ref) {...} } output_buffer = new OutputFrame(); while (true) { receive( (immutable (float) [] smpls) { add_to_buffer(smpls); output_data(); }, &output_buffer.set_rate, &output_buffer.set_clock_src1, &output_buffer.set_clock_src2, ); } On 27/09/2010 20:49, Juanjo Alvarez wrote:On Mon, 27 Sep 2010 21:00:48 +0200, Johannes Pfau wrote:On 27.09.2010 20:46, Juanjo Alvarez wrote:Yep, variants are cool. You could even use an struct as value type of the associative array and store the variant in one member and the signature of the delegate, as string, in another member. The you could use a mixin in the receiver to extract the delegate without knowing the original signature. All this is wonderfully disturbing to me :)I'm new to the language so I don't know if this is horribly wrong on some levels, but it works: ----------------------------- import std.variant; import std.stdio; class C { bool test(int i, char c) { writeln("Hello from test1"); return true; } void test2(string v) { writeln("Hello from test2, ", v); } } void main() { auto c = new C; Variant[string] holder = ["test": Variant(&c.test), "test2": Variant (&c.test2)]; receiver(holder); } void receiver(Variant[string] message) { // If you get the Variant template instantiation delegate // signature wrong, it will // be detected at compile time! auto t = message["test"].get!(bool delegate(int, char)); auto t2 = message["test2"].get!(void delegate(string)); t(1, 'c'); t2("foo"); } -------------------------- Curiously if you create holder like this, it will give an arrayoutofbound error at runtime, I don't know if that is a bug: void main() { auto c = new C; Variant[string] holder; holder["test"] = Variant(&c.test); holder["test2"] = Variant(&c.test2); }I totally forgot about Variant! As far as I know that's exactly what variant is for and it's way better than my proposed hack. The example you posted is perfectly fine as well. I'm not sure what causes the arrayoutofbound error, the second example is correct as well.
Sep 27 2010
On Mon, Sep 27, 2010 at 21:49, Juanjo Alvarez < juanjux thatwebmailofgoogleproperty.com> wrote:I think I got this one too. IIRC, it's a bug in the holder["test"] part than the Variant(&c.test) part.Curiously if you create holder like this, it will give an arrayoutofbound error at runtime, I don't know if that is a bug:Yep, variants are cool. You could even use an struct as value type of the associative array and store the variant in one member and the signature of the delegate, as string, in another member. The you could use a mixin in the receiver to extract the delegate without knowing the original signature. All this is wonderfully disturbing to me :)I'm not sure you can. You can only mixin strings known at compile-time. Your string member will only have a value at runtime. Except if the struct is an enum, maybe. Philippe
Sep 27 2010