Jump to page: 1 2
Thread overview
Call different member functions on object sequence with a generic handler function?
Jun 29, 2018
Robert M. Münch
Jun 29, 2018
Ali Çehreli
Jun 29, 2018
Robert M. Münch
Jun 29, 2018
Timoses
Jun 30, 2018
Jerry
Jul 01, 2018
Robert M. Münch
Jul 01, 2018
Basile B.
Jul 01, 2018
Timoses
Jun 29, 2018
Robert M. Münch
Jun 30, 2018
Ali Çehreli
Jun 29, 2018
Timoses
Jun 29, 2018
Timoses
Jun 30, 2018
Ali Çehreli
Jun 30, 2018
Basile B.
Jun 30, 2018
Basile B.
June 29, 2018
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

June 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
June 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:
> 
>> 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:

Hi, that was somehow in my mind but didn't made to get the syntax clear... Thanks a lot.

> 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

June 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:
>
>> 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?

My guess would be:

void handler(alias func, T)(T[] ts) {
    ....
}

>
> 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

It'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
June 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);
    }
June 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.
June 29, 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

June 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:
>
>> 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__):
> }

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...

Ali

June 30, 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.
June 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

« First   ‹ Prev
1 2