digitalmars.D.learn - Call different member functions on object sequence with a generic handler function?
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (36/36) Jun 29 2018 I hope this is understandable... I have:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (30/32) Jun 29 2018 Passing a lambda or a string mixin:
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (18/47) Jun 29 2018 Hi, that was somehow in my mind but didn't made to get the syntax
- Timoses (13/31) Jun 29 2018 My guess would be:
- Jerry (8/11) Jun 30 2018 Btw this is pretty much std.algorithm.each
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (8/18) Jun 30 2018 The looping needs to be done in the handler because there are two loops
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (12/50) Jun 29 2018 How does it work if one of the members takes an argument that is
- =?UTF-8?Q?Ali_=c3=87ehreli?= (34/52) Jun 29 2018 So the others still don't have a parameter?
- Timoses (43/75) Jun 29 2018 Trying to fiddle around a bit with delegates.. But why is the
- Timoses (14/17) Jun 29 2018 Aw.. Class = reference type so
- =?UTF-8?Q?Ali_=c3=87ehreli?= (17/19) Jun 29 2018 Casting the reference to void* produces the address of the object:
- Basile B. (31/63) Jun 29 2018 Using opDispatch we can manage to get a voldemort able to resolve
- Basile B. (2/75) Jun 30 2018 insert "in" at the right place.
I hope this is understandable... I have: class C { void A(); void B(); void C(); } I'm iterating over a set of objects of class C like: foreach(obj; my_selected_objs){ ... } The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc. foreach(obj; my_selected_objs){ ... obj.A|B|C() ... } So, how can I write a generic handler that does the iteration, where I can specify which member function to call? void do_A() { handler(C.A()); ??? } void do_B() { handler(C.B()); ??? } handler(???){ foreach(obj: my_selected_objs){ ??? } } Viele Grüsse. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
Jun 29 2018
On 06/29/2018 09:44 AM, Robert M. Münch wrote:So, how can I write a generic handler that does the iteration, where I can specify which member function to call?Passing a lambda or a string mixin: import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); } } void handler(alias func)(C[] cs) { foreach (c; cs) { func(c); } } void handler_2(string func)(C[] cs) { foreach (c; cs) { enum expr = "c." ~ func ~ "();"; mixin(expr); } } void main() { auto cs = [ new C(), new C() ]; handler!(o => o.A())(cs); handler!(o => o.B())(cs); handler_2!"A"(cs); handler_2!"B"(cs); } Ali
Jun 29 2018
On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said:On 06/29/2018 09:44 AM, Robert M. Münch wrote:Hi, that was somehow in my mind but didn't made to get the syntax clear... Thanks a lot.So, how can I write a generic handler that does the iteration, where I can specify which member function to call?Passing a lambda or a string mixin:import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); } } void handler(alias func)(C[] cs) { foreach (c; cs) { func(c); } }Is it possible to make C[] a template type so that I can use different classes and lambdas?void handler_2(string func)(C[] cs) { foreach (c; cs) { enum expr = "c." ~ func ~ "();"; mixin(expr); } }Ok, the "strange" syntax for me is the handler(alias func) or handler(string func) ... I'm alway thinkin in lines of a parameter... which of course doesn't work. Looking at the D grammer for functions these things should be the FuncDeclaratorSuffix, is this right? And then, which part does this fall into? FuncDeclaratorSuffix: Parameters MemberFunctionAttributesopt TemplateParameters Parameters MemberFunctionAttributesop -- Robert M. Münch http://www.saphirion.com smarter | better | faster
Jun 29 2018
On Friday, 29 June 2018 at 20:08:56 UTC, Robert M. Münch wrote:On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said:My guess would be: void handler(alias func, T)(T[] ts) { .... }On 06/29/2018 09:44 AM, Robert M. Münch wrote: void handler(alias func)(C[] cs) { foreach (c; cs) { func(c); } }Is it possible to make C[] a template type so that I can use different classes and lambdas?Ok, the "strange" syntax for me is the handler(alias func) or handler(string func) ... I'm alway thinkin in lines of a parameter... which of course doesn't work. Looking at the D grammer for functions these things should be the FuncDeclaratorSuffix, is this right? And then, which part does this fall into? FuncDeclaratorSuffix: Parameters MemberFunctionAttributesopt TemplateParameters Parameters MemberFunctionAttributesopIt's definitely the "TemplateParameters" one: void func(<template params>)(<params>) { ... } is the short form of template(<template params>) { void func(<params>) { ... } } https://dlang.org/spec/template.html
Jun 29 2018
On Friday, 29 June 2018 at 20:23:47 UTC, Timoses wrote:void handler(alias func, T)(T[] ts) { .... }Btw this is pretty much std.algorithm.each import std.algorithm; void main() { auto cs = [ new C(), new C() ]; cs.each!(o => o.A()); } https://dlang.org/phobos/std_algorithm_iteration.html#.each
Jun 30 2018
On 2018-06-30 22:53:47 +0000, Jerry said:Btw this is pretty much std.algorithm.each import std.algorithm; void main() { auto cs = [ new C(), new C() ]; cs.each!(o => o.A()); } https://dlang.org/phobos/std_algorithm_iteration.html#.eachThe looping needs to be done in the handler because there are two loops running one after the other and the range to loop over is detected in the handler too. Otherwise a lot of code duplication would happen. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
Jun 30 2018
On Sunday, 1 July 2018 at 06:55:35 UTC, Robert M. Münch wrote:On 2018-06-30 22:53:47 +0000, Jerry said:Look at my solution then: https://forum.dlang.org/post/kmkckipiwlvwahifelnc forum.dlang.orgBtw this is pretty much std.algorithm.each import std.algorithm; void main() { auto cs = [ new C(), new C() ]; cs.each!(o => o.A()); } https://dlang.org/phobos/std_algorithm_iteration.html#.eachThe looping needs to be done in the handler because there are two loops running one after the otherand the range to loop over is detected in the handler too. Otherwise a lot of code duplication would happen.
Jul 01 2018
On Sunday, 1 July 2018 at 06:55:35 UTC, Robert M. Münch wrote:The looping needs to be done in the handler because there are two loops running one after the other and the range to loop over is detected in the handler too. Otherwise a lot of code duplication would happen.Maybe an application for filter? C[] cs = ...; cs.filter!((c) => <predicate to be fulfilled>) .each!((c) => c.a())
Jul 01 2018
How does it work if one of the members takes an argument that is deduced inside the handler function? On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said:Passing a lambda or a string mixin: import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); }void C(bool flag) { writln(__FUNCTION__): }} void handler(alias func)(C[] cs) { foreach (c; cs) { func(c);func(c)(flag);} } void handler_2(string func)(C[] cs) { foreach (c; cs) { enum expr = "c." ~ func ~ "();"; mixin(expr); } } void main() { auto cs = [ new C(), new C() ]; handler!(o => o.A())(cs);How to get the parameter spec into the lambda?handler!(o => o.B())(cs); handler_2!"A"(cs); handler_2!"B"(cs); } Ali-- Robert M. Münch http://www.saphirion.com smarter | better | faster
Jun 29 2018
On 06/29/2018 02:40 PM, Robert M. Münch wrote:How does it work if one of the members takes an argument that is deduced inside the handler function? On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said:So the others still don't have a parameter? It's not clear how the general function should know what member function is being passed. One way is to check the signature of the lambda and decide to pass the flag or not. The other way is to always pass the flag but the caller does not use it. import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); } void C(bool flag) { writeln(__FUNCTION__); } } void handler(alias func)(C[] cs) { bool flag; foreach (c; cs) { func(c, flag); // Always passes the flag } } void main() { auto cs = [ new C(), new C() ]; // flag is used only sometimes handler!((o, flag) => o.A())(cs); handler!((o, flag) => o.B())(cs); handler!((o, flag) => o.C(flag))(cs); } But it started to feel unnatural at this point. What is the exact use case? Perhaps there are better ways... AliPassing a lambda or a string mixin: import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); }void C(bool flag) { writln(__FUNCTION__): }
Jun 29 2018
On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote:I hope this is understandable... I have: class C { void A(); void B(); void C(); } I'm iterating over a set of objects of class C like: foreach(obj; my_selected_objs){ ... } The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc. foreach(obj; my_selected_objs){ ... obj.A|B|C() ... } So, how can I write a generic handler that does the iteration, where I can specify which member function to call? void do_A() { handler(C.A()); ??? } void do_B() { handler(C.B()); ??? } handler(???){ foreach(obj: my_selected_objs){ ??? } } Viele Grüsse.Trying to fiddle around a bit with delegates.. But why is the context for delegates not working for classes?? https://run.dlang.io/is/Rxeukg import std.stdio; class Aclass { int i; void foo() { writeln("called ", i); } } struct Bstruct { int i; void foo() { writeln("called ", i); } } template callFoo(T) { alias Dun = void delegate(); void callFoo(T t) { Dun fun; fun.funcptr = &T.foo; fun.ptr = cast(void*)(&t); Dun gun; gun = &t.foo; writeln(fun.ptr, " (fun.ptr of " ~ T.stringof ~ ")"); writeln(gun.ptr, " (gun.ptr of " ~ T.stringof ~ ")"); writeln(&t, " (Address of instance (context))"); fun(); gun(); } } void main() { auto a = new Aclass(); a.i = 5; auto b = Bstruct(); b.i = 7; writeln("---- Doesn't work ----"); callFoo(a); writeln("\n---- Works ----"); callFoo(b); }
Jun 29 2018
On Friday, 29 June 2018 at 20:28:55 UTC, Timoses wrote:On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote: Trying to fiddle around a bit with delegates.. But why is the context for delegates not working for classes??Aw.. Class = reference type so class A { } struct B { } void delegate() del; A a = new A(); del.ptr = a; // NOT its address, as that would be the address of the reference on the stack B b = B(); del.ptr = &b // value type => address of object in stack ... How would one print the address of the object then though? Since &a is the address of the reference' types stack location. cast(void*)a would be on solution I guess.
Jun 29 2018
On 06/29/2018 02:11 PM, Timoses wrote:.... How would one print the address of the object then though? Since &a is the address of the reference' types stack location.Casting the reference to void* produces the address of the object: import std.stdio; class C { int i; } void main() { auto r = new C(); writeln("Reference is at ", &r); writeln("Object is at ", cast(void*)r); writeln("Member is at ", &r.i); } Sample output: Reference is at 7FFE735E6698 Object is at 7F78F02B0060 Member is at 7F78F02B0070 Ali
Jun 29 2018
On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote:I hope this is understandable... I have: class C { void A(); void B(); void C(); } I'm iterating over a set of objects of class C like: foreach(obj; my_selected_objs){ ... } The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc. foreach(obj; my_selected_objs){ ... obj.A|B|C() ... } So, how can I write a generic handler that does the iteration, where I can specify which member function to call? void do_A() { handler(C.A()); ??? } void do_B() { handler(C.B()); ??? } handler(???){ foreach(obj: my_selected_objs){ ??? } } Viele Grüsse.Using opDispatch we can manage to get a voldemort able to resolve the member func A, B or C etc. --- import std.stdio; class C { void A(){writeln(__FUNCTION__);} void B(int i){writeln(__FUNCTION__, " ", i);} } auto handler(T)(T t) { struct Handler { auto opDispatch(string member, Args...)(Args args) { import std.algorithm.iteration : each; mixin( `t.each!(a => a.` ~ member ~ `(args));` ); } } Handler h; return h; } void main() { auto cs = [new C(), new C()]; handler(cs).A(); cs.handler.B(42); // UFCS style } --- which results a very natural expression.
Jun 29 2018
On Saturday, 30 June 2018 at 00:16:49 UTC, Basile B. wrote:On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote:insert "in" at the right place.I hope this is understandable... I have: class C { void A(); void B(); void C(); } I'm iterating over a set of objects of class C like: foreach(obj; my_selected_objs){ ... } The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc. foreach(obj; my_selected_objs){ ... obj.A|B|C() ... } So, how can I write a generic handler that does the iteration, where I can specify which member function to call? void do_A() { handler(C.A()); ??? } void do_B() { handler(C.B()); ??? } handler(???){ foreach(obj: my_selected_objs){ ??? } } Viele Grüsse.Using opDispatch we can manage to get a voldemort able to resolve the member func A, B or C etc. --- import std.stdio; class C { void A(){writeln(__FUNCTION__);} void B(int i){writeln(__FUNCTION__, " ", i);} } auto handler(T)(T t) { struct Handler { auto opDispatch(string member, Args...)(Args args) { import std.algorithm.iteration : each; mixin( `t.each!(a => a.` ~ member ~ `(args));` ); } } Handler h; return h; } void main() { auto cs = [new C(), new C()]; handler(cs).A(); cs.handler.B(42); // UFCS style } --- which results a very natural expression.
Jun 30 2018