www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - how to do member function pointer in D?

reply newbie <some where.com> writes:
Hi,

I want to be able to create a member function pointer type from a class (not
from an object of that class), i.e.

class A {
  void f() {}
  void g() {}
}

(member function pointer) mfp = &A.f; // what's the sytax for the type?

// also I want the compiler to report error if I pass g() to mfp:
mfp = &A.g;   // type error!

// and mfp can be invoked on different object instance of A:
A a1, a2;

mfp(a1);   // call a1.f(), what's the right syntax?
mfp(a2);   // call a2.f()

Thanks.
Jul 30 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Although people have presented hacks to do this, there isn't a standard 
way to do this in D.

Of course, you could use a function literal to accomplish this:
   mfp = function void(A obj) { obj.f(); };
That isn't techically a member function pointer, but it is pretty similar.

Do you have a compelling use case where you need member-function-pointer 
but delegates or the function literal above wouldn't work?  I haven't 
yet heard of one, but of course they might exist. :)

Russ

newbie wrote:
 Hi,
 
 I want to be able to create a member function pointer type from a class (not
 from an object of that class), i.e.
 
 class A {
   void f() {}
   void g() {}
 }
 
 (member function pointer) mfp = &A.f; // what's the sytax for the type?
 
 // also I want the compiler to report error if I pass g() to mfp:
 mfp = &A.g;   // type error!
 
 // and mfp can be invoked on different object instance of A:
 A a1, a2;
 
 mfp(a1);   // call a1.f(), what's the right syntax?
 mfp(a2);   // call a2.f()
 
 Thanks.
Jul 30 2008
parent reply newbie <some where.com> writes:
The main problem is that I want to let the D compiler check the type for me:
e.g.

mfp1 = function void(A obj) { obj.f(); };
mfp2 = function void(A obj) { obj.g(); };
void function(A) fp;   // suppose fp is what I intended to call A.f()

fp = mfp1;    // cass 1: OK
fp = mfp2;    // cass 2: OK
mfp1 = mfp2;  // cass 3: also OK

Of course this is because fp is specified by the signature of it's arguments
type
and return type.

I want a member function pointer type that is more strict than this, i.e. both
case (2 & 3) will cause compiler type error.

Another minor issue with your suggested approach is that: I have to write those
wrappers for all the member function that I want to use.


== Quote from Russell Lewis (webmaster villagersonline.com)'s article
 Although people have presented hacks to do this, there isn't a standard
 way to do this in D.
 Of course, you could use a function literal to accomplish this:
    mfp = function void(A obj) { obj.f(); };
 That isn't techically a member function pointer, but it is pretty similar.
 Do you have a compelling use case where you need member-function-pointer
 but delegates or the function literal above wouldn't work?  I haven't
 yet heard of one, but of course they might exist. :)
 Russ
 newbie wrote:
 Hi,

 I want to be able to create a member function pointer type from a class (not
 from an object of that class), i.e.

 class A {
   void f() {}
   void g() {}
 }

 (member function pointer) mfp = &A.f; // what's the sytax for the type?

 // also I want the compiler to report error if I pass g() to mfp:
 mfp = &A.g;   // type error!

 // and mfp can be invoked on different object instance of A:
 A a1, a2;

 mfp(a1);   // call a1.f(), what's the right syntax?
 mfp(a2);   // call a2.f()

 Thanks.
Jul 30 2008
parent reply BCS <ao pathlink.com> writes:
Reply to Newbie,

 The main problem is that I want to let the D compiler check the type
 for me: e.g.
 
 mfp1 = function void(A obj) { obj.f(); };
 mfp2 = function void(A obj) { obj.g(); };
 void function(A) fp;   // suppose fp is what I intended to call A.f()
 fp = mfp1;    // cass 1: OK
 fp = mfp2;    // cass 2: OK
 mfp1 = mfp2;  // cass 3: also OK
 Of course this is because fp is specified by the signature of it's
 arguments type and return type.
 
 I want a member function pointer type that is more strict than this,
 i.e. both case (2 & 3) will cause compiler type error.
 
That is not something the type system can do. The two methods operate on the same object type, take the same args and return the same type. As far as the type system system is concerned, they are identical. Maybe I'm missing something because what you seem to want doesn't seem useful to me, the restriction you seem to want would restrict the allowable values for fp to exactly one. If this is so, why do you want a variable? The only use I can think of is if you want to call a the f method from a base class on an object of a derived class. If this is the case you are subverting the type system so you are on your own.
 Another minor issue with your suggested approach is that: I have to
 write those wrappers for all the member function that I want to use.
 
 == Quote from Russell Lewis (webmaster villagersonline.com)'s article
 
 Although people have presented hacks to do this, there isn't a
 standard
 way to do this in D.
 Of course, you could use a function literal to accomplish this:
 mfp = function void(A obj) { obj.f(); };
 That isn't techically a member function pointer, but it is pretty
 similar.
 Do you have a compelling use case where you need
 member-function-pointer
 but delegates or the function literal above wouldn't work?  I haven't
 yet heard of one, but of course they might exist. :)
 Russ
 newbie wrote:
 Hi,
 
 I want to be able to create a member function pointer type from a
 class (not from an object of that class), i.e.
 
 class A {
 void f() {}
 void g() {}
 }
 (member function pointer) mfp = &A.f; // what's the sytax for the
 type?
 
 // also I want the compiler to report error if I pass g() to mfp:
 mfp = &A.g;   // type error!
 
 // and mfp can be invoked on different object instance of A: A a1,
 a2;
 
 mfp(a1);   // call a1.f(), what's the right syntax? mfp(a2);   //
 call a2.f()
 
 Thanks.
 
Jul 30 2008
parent reply newbie <some where.com> writes:
 Maybe I'm missing something because what you seem to want doesn't seem useful
 to me, the restriction you seem to want would restrict the allowable values
 for fp to exactly one. If this is so, why do you want a variable?
I want my code to manipulate at function ptr level (instead of just calling the function). For now maybe what I can do is declare an invariant variable, which after initialization cannot be assigned to again. But I have trouble to get this code compiled: class A { void f() {writefln("f()");} void g() {writefln("g()");} } alias void function(A) FP; class B { static invariant FP mfp1 = function void(A obj) {obj.f();}; // line 11 } $ dmd memberfunptr.d memberfunptr.d(11): Error: cannot implicitly convert expression (__funcliteral1) of type void function(A) to invariant(void function(A)) Why I need to explicitly cast it? and even after I change the line to: static invariant FP mfp1 = cast(invariant FP)(function void(A obj) {obj.f();}); It says: $ dmd memberfunptr.d memberfunptr.d(11): Error: non-constant expression __funcliteral1 Anyone know what's the right way to write this? Thanks.
Jul 30 2008
parent reply BCS <ao pathlink.com> writes:
Reply to Newbie,

 Maybe I'm missing something because what you seem to want doesn't
 seem useful to me, the restriction you seem to want would restrict
 the allowable values for fp to exactly one. If this is so, why do you
 want a variable?
 
I want my code to manipulate at function ptr level (instead of just calling the function). For now maybe what I can do is declare an invariant variable, which after initialization cannot be assigned to again. But I have trouble to get this code compiled: class A { void f() {writefln("f()");} void g() {writefln("g()");} } alias void function(A) FP; class B { static invariant FP mfp1 = function void(A obj) {obj.f();};// line 11 }
[...]
 static invariant FP mfp1 = cast(invariant FP)(function void(A obj)
 {obj.f();});
 
 It says:
 
 $ dmd memberfunptr.d
 memberfunptr.d(11): Error: non-constant expression __funcliteral1
to clear that error: static invariant FP mfp1; static this() { mfp1 = cast(invariant FP)(function void(A obj){obj.f();}); } OTOH I still have no clue what you are trying to do. I suspect their is a simperer way to do what you want. That said, /I/ often /enjoy/ doing things the far from simple way. <g>
Jul 30 2008
parent reply newbie <some where.com> writes:
 to clear that error:
 static invariant FP mfp1;
 static this()
 {
  mfp1 = cast(invariant FP)(function void(A obj){obj.f();});
 }
Thanks. Two more questions: 1) why the cast is necessary? shall I report a bug? e.g. invariant int a = 1; // I don't need the cast here! 2) how to do it as global variables? e.g. If I pull out it from B, and define as global variable: invariant FP mfp2 = cast(invariant FP)(function void(A obj) {obj.f();}); $ dmd memberfunptr.d memberfunptr.d(10): Error: non-constant expression __funcliteral1
 OTOH I still have no clue what you are trying to do. I suspect their is a
 simperer way to do what you want.
 That said, /I/ often /enjoy/ doing things the far from simple way. <g>
I need to hold a collection of member-function pointers, and manipulate it in some way, then later make function calls on different object via these pointers. I want to protect myself that any these pointers shouldn't be re-assigned to other member functions with the same signatures.
Jul 30 2008
parent reply BCS <ao pathlink.com> writes:
Reply to Newbie,

 to clear that error:
 static invariant FP mfp1;
 static this()
 {
 mfp1 = cast(invariant FP)(function void(A obj){obj.f();});
 }
Thanks. Two more questions: 1) why the cast is necessary? shall I report a bug? e.g. invariant int a = 1; // I don't need the cast here! 2) how to do it as global variables? e.g. If I pull out it from B, and define as global variable: invariant FP mfp2 = cast(invariant FP)(function void(A obj) {obj.f();}); $ dmd memberfunptr.d memberfunptr.d(10): Error: non-constant expression __funcliteral1
same solution as befor (the issue is that the only thing you can put after the '=' ouside of a function is a constant expression and a function litteral isn't one) //at global scope (OTOH static's are globals) static invariant FP mfp1; static this() { mfp1 = cast(invariant FP)(function void(A obj){obj.f();}); }
 OTOH I still have no clue what you are trying to do. I suspect their
 is a
 simperer way to do what you want.
 That said, /I/ often /enjoy/ doing things the far from simple way.
 <g>
I need to hold a collection of member-function pointers, and manipulate it in some way, then later make function calls on different object via these pointers. I want to protect myself that any these pointers shouldn't be re-assigned to other member functions with the same signatures.
I still don't get it, what type of manipulation (outside self modifying code) can you do that doesn't allow switching in a different function with the same signature?
Jul 30 2008
parent reply newbie <some where.com> writes:
 same solution as befor (the issue is that the only thing you can put after
 the '=' ouside of a function is a constant expression and a function litteral
 isn't one)
Why a function literal is not a constant expression? Especially after I defining a global top level wrapper function in this case. Under the hood, it should just be a raw pointer to some memory address, why this cannot be a constant?
 //at global scope (OTOH static's are globals)
 static invariant FP mfp1;
 static this()
 {
 mfp1 = cast(invariant FP)(function void(A obj){obj.f();});
 }
Thanks again. I can live with this workaround right now, but I'd really like to write it as simple as: invariant FP mfp2 = function void(A obj) {obj.f();}; // without the cast
 I still don't get it, what type of manipulation (outside self modifying code)
E.g. save in a hash-table, or use them as keys ... And I'd really like to do self modifying code ;-) I read somewhere that D plan have to AST macros? so we are closer to lisp: http://en.wikipedia.org/wiki/Greenspun%27s_Tenth_Rule
 can you do that doesn't allow switching in a different function with the
 same signature?
Yes, I do it manually (by writing program carefully). I want the help from the type system (or the language compiler) to protect me from such violation.
Jul 30 2008
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Newbie,

 same solution as befor (the issue is that the only thing you can put
 after the '=' ouside of a function is a constant expression and a
 function litteral isn't one)
 
Why a function literal is not a constant expression? Especially after I defining a global top level wrapper function in this case. Under the hood, it should just be a raw pointer to some memory address, why this cannot be a constant?
don't ask me.
 //at global scope (OTOH static's are globals)
 static invariant FP mfp1;
 static this()
 {
 mfp1 = cast(invariant FP)(function void(A obj){obj.f();});
 }
Thanks again. I can live with this workaround right now, but I'd really like to write it as simple as: invariant FP mfp2 = function void(A obj) {obj.f();}; // without the cast
 I still don't get it, what type of manipulation (outside self
 modifying code)
 
E.g. save in a hash-table, or use them as keys ...
but neither of those will be usefull unless you can assign more than one value to the type what I'm reading (and I must be missing somthing) is somthing like a hash table where the keys are the number 5 to the values are the number 3. One idea on what I'm missing; Do you want nothing at all to be assigname to the variable after the fist assigment? class Bob {void a(){} void b(){} } The_Type fnp = Bob.a; fnp = Bob.a; // valid or not? Do you care if other instances of the same type have pointers to other function? The_Type fnp = Bob.a;
 And I'd really like to do self modifying code ;-) I read somewhere
 that D plan have to AST macros? so we are closer to lisp:
 http://en.wikipedia.org/wiki/Greenspun%27s_Tenth_Rule
 
IIRC that is with regards to program internals, not the external interface
 can you do that doesn't allow switching in a different function with
 the same signature?
 
Yes, I do it manually (by writing program carefully). I want the help from the type system (or the language compiler) to protect me from such violation.
Jul 30 2008
parent reply u <e mail.com> writes:
 Do you want nothing at all to be assigname to the variable after the fist
 assigment?
 class Bob {void a(){} void b(){} }
 The_Type fnp = Bob.a;
 fnp = Bob.a; // valid or not?
Can fnp be invoked on an actual object? and what's the syntax? Bob bob = new Bob(); fnp(bob); // ? how to make this call?
 Do you care if other instances of the same type have pointers to other
function?
 The_Type fnp = Bob.a;
Jul 30 2008
parent BCS <ao pathlink.com> writes:
Reply to u,

 Do you want nothing at all to be assigname to the variable after the
 fist
 assigment?
 class Bob {void a(){} void b(){} }
 The_Type fnp = Bob.a;
 fnp = Bob.a; // valid or not?
Can fnp be invoked on an actual object? and what's the syntax?
the whole thing is hypothetical so ...
 Bob bob = new Bob();
 fnp(bob);  // ? how to make this call?
 Do you care if other instances of the same type have pointers to
 other function? The_Type fnp = Bob.a;
 
Jul 31 2008
prev sibling parent reply JAnderson <ask me.com> writes:
newbie wrote:
 same solution as befor (the issue is that the only thing you can put after
 the '=' ouside of a function is a constant expression and a function litteral
 isn't one)
Why a function literal is not a constant expression? Especially after I defining a global top level wrapper function in this case. Under the hood, it should just be a raw pointer to some memory address, why this cannot be a constant?
 //at global scope (OTOH static's are globals)
 static invariant FP mfp1;
 static this()
 {
 mfp1 = cast(invariant FP)(function void(A obj){obj.f();});
 }
Thanks again. I can live with this workaround right now, but I'd really like to write it as simple as: invariant FP mfp2 = function void(A obj) {obj.f();}; // without the cast
 I still don't get it, what type of manipulation (outside self modifying code)
E.g. save in a hash-table, or use them as keys ... And I'd really like to do self modifying code ;-) I read somewhere that D plan have to AST macros? so we are closer to lisp: http://en.wikipedia.org/wiki/Greenspun%27s_Tenth_Rule
 can you do that doesn't allow switching in a different function with the
 same signature?
Yes, I do it manually (by writing program carefully). I want the help from the type system (or the language compiler) to protect me from such violation.
I'm not sure I completely understand either but I'll take a stab. What about using polymorphism? Where delegates can be any type of object interfaces restrict what sort of objects can be used with your hash-table. -Joel
Jul 30 2008
parent reply u <e mail.com> writes:
 I'm not sure I completely understand either but I'll take a stab.  What
 about using polymorphism?  Where delegates can be any type of object
 interfaces restrict what sort of objects can be used with your hash-table.
Go back to my original question: How to create a variable which hold a particular function pointer of a class, and can be invoked on different objects of that class: fp = &(A.f); A a1, a2; a1.fp(); // how to make this invocation work? a2.fp(); And I have one more requirement that even if A.f() and A.g() have same signature, fp = &(A.g); // expect compiler report error here. How to declare the type of such fp?
Jul 30 2008
next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
u wrote:
I'm not sure I completely understand either but I'll take a stab.  What
about using polymorphism?  Where delegates can be any type of object
interfaces restrict what sort of objects can be used with your hash-table.
Go back to my original question: How to create a variable which hold a particular function pointer of a class, and can be invoked on different objects of that class: fp = &(A.f); A a1, a2; a1.fp(); // how to make this invocation work? a2.fp(); And I have one more requirement that even if A.f() and A.g() have same signature, fp = &(A.g); // expect compiler report error here. How to declare the type of such fp?
There is a current thread in digitalmars.D.learn titled "Pointer to member variable again." It has turned into a discussion of this very topic. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Jul 30 2008
parent u <e mail.com> writes:
== Quote from Kirk McDonald (kirklin.mcdonald gmail.com)'s article
 u wrote:
 Go back to my original question:

 How to create a variable which hold a particular function pointer of a class,
and
 can be invoked on different objects of that class:

 fp = &(A.f);
 A a1, a2;
 a1.fp();   // how to make this invocation work?
 a2.fp();

 And I have one more requirement that even if A.f() and A.g() have same
signature,

 fp = &(A.g);   // expect compiler report error here.

 How to declare the type of such fp?
There is a current thread in digitalmars.D.learn titled "Pointer to member variable again." It has turned into a discussion of this very topic.
I had hoped that D will offer better solution than C++'s member function pointer. Looks like currently it's more difficulty to do what I want in D. Probably I will live with the wrapper function for now.
Jul 31 2008
prev sibling parent JAnderson <ask me.com> writes:
u wrote:
 I'm not sure I completely understand either but I'll take a stab.  What
 about using polymorphism?  Where delegates can be any type of object
 interfaces restrict what sort of objects can be used with your hash-table.
Go back to my original question: How to create a variable which hold a particular function pointer of a class, and can be invoked on different objects of that class: fp = &(A.f); A a1, a2; a1.fp(); // how to make this invocation work? a2.fp(); And I have one more requirement that even if A.f() and A.g() have same signature, fp = &(A.g); // expect compiler report error here. How to declare the type of such fp?
//What about something like: void funcBind(Obj, alias Func)(Obj obj) { obj.Func(); } ... alias funcBind!(A, f) fp; A a1, a2; fp(a1); fp(a2); alias funcBind!(A, g) fp; //Compiler error -> Duplicate //Note with a little more work you could make A implicit //and therefore have any class Type as the first parameter. I can't really see why function/member pointers are necessary for this situation since Member pointers are one to many and you seem to want a one-to-one relationship. -Joel
Jul 31 2008