www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Pointers to non-static member functions!

reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
Currently, this compiles:

class A
{
    void func() {}
}

void main()
{
  auto p = &A.func;
}

In this case, typeof(p) is void function().
Calling one of these pointers, of course, can easily give you a segfault as 
it completely ignores the this pointer.
I didn't even realize you could do this until I saw 
http://d.puremagic.com/issues/show_bug.cgi?id=5986

I understand that it could be useful to have a way to get the address of a 
non-static member function, but I doubt returning a malformed function 
pointer is really useful.

Does anybody think changing &ClassType.nonStaticMember to return void* would 
be a bad idea? 
Jun 08 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 04:00:53 -0400, "Daniel Murphy" <yebblies nospamgmail.com> said:

 Currently, this compiles:
 
 class A
 {
     void func() {}
 }
 
 void main()
 {
   auto p = &A.func;
 }
 
 In this case, typeof(p) is void function().
 Calling one of these pointers, of course, can easily give you a segfault as
 it completely ignores the this pointer.
 I didn't even realize you could do this until I saw
 http://d.puremagic.com/issues/show_bug.cgi?id=5986
 
 I understand that it could be useful to have a way to get the address of a
 non-static member function, but I doubt returning a malformed function
 pointer is really useful.
 
 Does anybody think changing &ClassType.nonStaticMember to return void* would
 be a bad idea?

I think it should work like my D/Objective-C language extension does it for selectors. <http://michelf.com/projects/d-objc/syntax/#selector-literals> &A.func should return a *member* function pointer which wants a 'this' parameter, and when you call it you should be required to add the 'this' argument at the beginning of the argument list, like this: void main() { auto p = &A.func; p(new A); } That'll probably require a syntax to specify a function type that wants a this pointer. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Michel Fortin" <michel.fortin michelf.com> wrote in message 
news:isnj6i$2afd$1 digitalmars.com...
 I think it should work like my D/Objective-C language extension does it 
 for selectors.
 <http://michelf.com/projects/d-objc/syntax/#selector-literals>

 &A.func should return a *member* function pointer which wants a 'this' 
 parameter, and when you call it you should be required to add the 'this' 
 argument at the beginning of the argument list, like this:

This would be nice to have, but the compiler would need to use a different calling convention or generate multiple function beginnings, as the this parameter must be passed last. This case is related to http://d.puremagic.com/issues/show_bug.cgi?id=2672
Jun 08 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 09:24:43 -0400, "Daniel Murphy" <yebblies nospamgmail.com> said:

 This would be nice to have, but the compiler would need to use a different
 calling convention or generate multiple function beginnings, as the this
 parameter must be passed last.

True. What I mean is that a function type should know whether it needs a 'this' pointer or not, and implicit conversion between a function type that needs a this pointer and one that doesn't need one should be forbidden. And calling such a function directly would either not work, or would require a 'this' to be provided as the first argument (which is then put at the right place according to the ABI rules). -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Michel Fortin" <michel.fortin michelf.com> wrote in message 
news:isoa8d$nif$1 digitalmars.com...
 True. What I mean is that a function type should know whether it needs a 
 'this' pointer or not, and implicit conversion between a function type 
 that needs a this pointer and one that doesn't need one should be 
 forbidden. And calling such a function directly would either not work, or 
 would require a 'this' to be provided as the first argument (which is then 
 put at the right place according to the ABI rules).

Ah I see. This could probably be implemented quite easily, but I doubt it's worth the effort. I think most cases can be done by casting and using a delegate. I don't think pointers to members brought a lot to C++ (apart from complexity and syntax) and they seem mostly unnecessary with D's delegates.
Jun 08 2011
prev sibling next sibling parent reply Trass3r <un known.com> writes:
Am 08.06.2011, 10:00 Uhr, schrieb Daniel Murphy <yebblies nospamgmail.com>:

 Currently, this compiles:

 class A
 {
     void func() {}
 }

 void main()
 {
   auto p = &A.func;
 }

 In this case, typeof(p) is void function().

 Does anybody think changing &ClassType.nonStaticMember to return void*  
 would be a bad idea?

?? Shouldn't this just return a delegate?
Jun 08 2011
next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Trass3r" <un known.com> wrote in message news:op.vwq80v023ncmek enigma...
 ??
 Shouldn't this just return a delegate?

I don't think getting a delegate makes any sense without an instance. I'm talking about this case: class A { void func(); } void main() { // returns a nonsense function pointer auto f = &A.func; // returns a working delegate auto a = new A(); auto g = &a.func; }
Jun 08 2011
parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:op.vwrgycgjeav7ka localhost.localdomain...
 The reason is to allow composition of delegates (not that I think this is 
 a worthy reason):

 class A
 {
    void func();
    void func2();
 }

 void main()
 {
    auto f = &A.func2;
    auto a = new A();
    auto g = &a.func; // delegate
    g.funcptr = f;
    g(); // calls a.func2()
 }

 I'd argue that a much more useful return type would be a delegate with the 
 this pointer set to null, but then I don't know what funcptr would 
 return.  I almost think you need a separate type for it, which seems like 
 a lot of effort for something that's hardly used.

 -Steve

I can see this being useful, but I think it should be done by having delegate.funcptr be a void* and &ClassType.nonstaticmemberfunction return void*. The type safety provided by the current way it works is an illusion, as the following compiles: class A { void func() { do something using member variables or the vtable etc } } class B { void func() {} } void main() { auto b = new B(); auto dg = &b.func; dg.funcptr = &A.func; dg(); // Probably a segfault }
Jun 08 2011
next sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:op.vwridsuteav7ka localhost.localdomain...
 Yes, but removing type safety does not prevent that from happening, plus 
 it allows something like this:

 class A
 {
   void func();
   int func2();
 }

 void main()
 {
    auto a = new A;
    auto dg = &a.func2();
    dg.funcptr = &A.func; // works if dg.funcptr and &A.func are void*, but 
 doesn't work today
    int x = dg(); // runs and returns garbage
 }

type, it _will_ work today!
 I almost would prefer that hacking delegates would be illegal.  Yes, you 
 can get the function pointer and data pointer out of a delegate, but 
 cannot set them.  I can't think of any good use cases for them.

I think you're right on this. I'll have a look and see how difficult making the delegate properties readonly is. I have actually needed to manually construct a delegate when doing low level calling convention stuff, but you can always do this using unions or casts if you have to.
 I'm mixed on whether you should be able to get a member "function 
 pointer".  It would be nice to simply make it a normal function pointer 
 that you can call with the appropriate type.

 BTW, if the calling convention is different, we may be able to allow it 
 via creating a "this" function pointer:

 assert(is(typeof(&A.func2) == int function(A this)));

 Since this is a keyword, it can be interpreted as a different calling 
 convention.

 -Steve

I can see the theoretical appeal of having member function pointers or being able to call member functions as if they were globals, but I don't think the practical uses really justify introducing new syntax or types or changing the ABI. I also don't think any option which does any of those things has a chance of getting incorporated into dmd. If I can get some kind of consensus I'll try and patch dmd. I think the following covers most of your points, given that you can still do the unsafe thing by casting: Make delegate.funcptr read only and return void* Make &ClassType.nonstaticmemberfunction return void*
Jun 08 2011
prev sibling next sibling parent Daniel Gibson <metalcaedes gmail.com> writes:
Am 08.06.2011 16:54, schrieb Steven Schveighoffer:
 
 I almost would prefer that hacking delegates would be illegal.  Yes, you
 can get the function pointer and data pointer out of a delegate, but
 cannot set them.  I can't think of any good use cases for them.
 
 I'm mixed on whether you should be able to get a member "function
 pointer".  It would be nice to simply make it a normal function pointer
 that you can call with the appropriate type.

That'd be nice. I think having a possibility to get a pointer to a member function that you can use with any instance of the class the method belongs to would be nice. Currently this should be possible by using a delegate and changing its .ptr to the object you want to call the method on (this won't work anymore if the delegates internal pointers are read-only as suggested above). This could be used for something like runtime-reflection (like Java's Method class - which is horribly slow btw, compared to a direct call to a method. For whatever reason.) So you could use object.classinfo.getMembers(), look for the method you want to use (with the name given at runtime!) and then use a function pointer to that Method to efficiently call it on any object of the same type. (So much for the theory, I don't see a way to find out the methods signature to match it to the signature you want, especially for overloaded methods - but maybe I just missed it.) BTW: MemberInfo (and MemberInfo_field and MemberInfo_function) should be documented in the object documentation. And what does MemberInfo_function's typeInfo() return? And is there a way to get a methods signature from MemberInfo_function? (I hope this made sense and I didn't ignore a nicer way to do this - at runtime - that is already implemented) Cheers, - Daniel
Jun 08 2011
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 10:54:54 -0400, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy  
 <yebblies nospamgmail.com> wrote:
 
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vwrgycgjeav7ka localhost.localdomain...
 
 The reason is to allow composition of delegates (not that I think this  is
 a worthy reason):
 
 class A
 {
    void func();
    void func2();
 }
 
 void main()
 {
    auto f = &A.func2;
    auto a = new A();
    auto g = &a.func; // delegate
    g.funcptr = f;
    g(); // calls a.func2()
 }
 
 I'd argue that a much more useful return type would be a delegate with  the
 this pointer set to null, but then I don't know what funcptr would
 return.  I almost think you need a separate type for it, which seems  like
 a lot of effort for something that's hardly used.
 
 -Steve

I can see this being useful, but I think it should be done by having delegate.funcptr be a void* and &ClassType.nonstaticmemberfunction return void*. The type safety provided by the current way it works is an illusion, as the following compiles: class A { void func() { do something using member variables or the vtable etc } } class B { void func() {} } void main() { auto b = new B(); auto dg = &b.func; dg.funcptr = &A.func; dg(); // Probably a segfault }

Yes, but removing type safety does not prevent that from happening, plus it allows something like this: class A { void func(); int func2(); } void main() { auto a = new A; auto dg = &a.func2(); dg.funcptr = &A.func; // works if dg.funcptr and &A.func are void*, but doesn't work today int x = dg(); // runs and returns garbage } I almost would prefer that hacking delegates would be illegal. Yes, you can get the function pointer and data pointer out of a delegate, but cannot set them. I can't think of any good use cases for them.

I was "hacking delegates" a lot in the D/Objective-C bridge (before I decided to bring things directly in the compiler). To make it short, I needed to do that to call the appropriate D function from Objective-C stub method implementation.
 BTW, if the calling convention is different, we may be able to allow it 
  via creating a "this" function pointer:
 
 assert(is(typeof(&A.func2) == int function(A this)));
 
 Since this is a keyword, it can be interpreted as a different calling  
 convention.

I was thinking about that too. Note that it forces int function(A this) to be implicitly castable to int function(void* this) when assigning to a delegate. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 13:29:27 -0400, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Wed, 08 Jun 2011 13:07:50 -0400, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 
 On 2011-06-08 10:54:54 -0400, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:
 
 On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy   
 <yebblies nospamgmail.com> wrote:
 
  I almost would prefer that hacking delegates would be illegal.  Yes,  
 you  can get the function pointer and data pointer out of a delegate,  
 but  cannot set them.  I can't think of any good use cases for them.

I was "hacking delegates" a lot in the D/Objective-C bridge (before I decided to bring things directly in the compiler). To make it short, I needed to do that to call the appropriate D function from Objective-C stub method implementation.

The issue with hacking delegates I have is that almost certainly you know what the type of the function pointer is, which means you almost certainly have access to the member function for that type directly, it seems a very strange use case to be able to dynamically address the member functions of a class without knowing the type. When I first wrote the above reason, I tried to think of a compelling real example, I couldn't. Now, you are implementing a bridge to another language that supports a feature, which means you have to implement it. But how often is that feature used in that other language?

This is not at all a feature of Objective-C. This was a workaround. Tell me, if inside a template you have an alias to a member function, how can I call that member function? This won't work: void callMe(alias memberFunc)(Object o) { o.memberFunc(); // won't work, Object has no member called "memberFunc". } What you can do is this: template Binding(alias memberFunc)(Object o) { void delegate() delegateToMember; delegateToMember.ptr = o; delegateToMember.funcptr = &memberFunc; delegateToMember(); } Although even there it won't work very well if your member is a virtual function. I needed to use an ever stranger workaround for that. Here's the actual code from the Objective-C bridge (it's a template which be mixed in the class): /** * Template which can be mixed in a class to bind selector sel to instance * method. * * This will create a receiver function which will forward the call to * method, decapsulating arguments and encapsulating the return value as * appropriate. */ template ObjcBindMethod(alias method, R, char[] sel, A...) { /** * Resolve virtual function and return a delegate to it. This must be * done from a non-static member function otherwise we can't get the * address of the overriding function if there is one. */ private R delegate(A) resolveVirtualCall() { return &method; } /** Call forwarder for a virtual method of this class. */ private static R forwardVirtualCall(objc.runtime.id self, objc.runtime.SEL _cmd, A args) { R delegate(A) delegate() resolve; resolve.ptr = objc.msg.send!(void*)(self, objc.method.selector!("d_object")); resolve.funcptr = &resolveVirtualCall; return resolve()(args); } mixin objc.bridge.ObjcMethodInfo!(forwardVirtualCall, R, sel, A); } Here, the entry point from Objective-C is the forwardVirtualCall function, which does two things: it finds the object pointer, and then it resolves the virtual call, which can only be done in a non-static member function (resolveVirtualCall) because in the absence of an implicit this pointer it won't work. Actually that's not really the entry point from Objective-C, there's a first entry point that performs argument conversion as necessary which then calls this one to call the right virtual function, but that's irrelevant to our case. What would have really simplified things in all this is a C++-style pointer to member function type. But that's not part of D.
 BTW, if the calling convention is different, we may be able to allow it 
   via creating a "this" function pointer:
  assert(is(typeof(&A.func2) == int function(A this)));
  Since this is a keyword, it can be interpreted as a different calling  
  convention.

I was thinking about that too. Note that it forces int function(A this) to be implicitly castable to int function(void* this) when assigning to a delegate.

ATM, delegates and functions do not implicitly cast whatsoever. In fact, I would not want the above cast to succeed, what should be implicitly cast is a contravariant function. For example int function(Object this) should implicitly cast to int function(A this).

You're right.
 Now, a delegate does not record its 'this' type, so getting the 
 function  pointer for the delegate should yield an uncallable function 
 pointer.  I  proposed in another part of this thread the syntax:
 
 int function(void this);
 
 This at least gives you type information, but doesn't allow you to  
 unsafely call it.  If you wish to explicitly cast it to a viable 
 function,  you can.

Makes sense.
 All this is dependent on the idea that a delegate cannot be constructed 
  unless you have the original method (or a type-safe 
 'delegate-function'  such as int function(A this)).  I really think 
 that makes sense.

I won't disagree with anything you say, because I do agree. I know my use case is a fringe one, and I don't need it anymore so I don't care much. And it'd only need one small thing for it to work without all that cumbersome hack: o.memberFunc() // where methodFunc is an alias to a member of o which probably shouldn't be that difficult to implement in the compiler, what's needed is new syntax to distinguish it from a normal member call. Perhaps this? o.(memberFunc)() -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 14:13:46 -0400, Michel Fortin <michel.fortin michelf.com> said:

 I won't disagree with anything you say, because I do agree. I know my 
 use case is a fringe one, and I don't need it anymore so I don't care 
 much. And it'd only need one small thing for it to work without all 
 that cumbersome hack:
 
 	o.memberFunc() // where methodFunc is an alias to a member of o
 
 which probably shouldn't be that difficult to implement in the 
 compiler, what's needed is new syntax to distinguish it from a normal 
 member call. Perhaps this?
 
 	o.(memberFunc)()

Now that I think about it, perhaps UFCS would make all this unnecessary. void callMe(alias memberFunc)(Object o) { o.memberFunc(); // error, no member called "memberFunc" in o memberFunc(o); // works? } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Michel Fortin" <michel.fortin michelf.com> wrote in message 
news:isog18$13vc$1 digitalmars.com...
 Now that I think about it, perhaps UFCS would make all this unnecessary.

 void callMe(alias memberFunc)(Object o) {
 o.memberFunc(); // error, no member called "memberFunc" in o
 memberFunc(o); // works?
 }

Somebody recently suggested making a parameter to enable a function to be called with ufcs. void func(int a, int b, Object this) {} A pointer to a function like this could be the same type as a member function pointer.
Jun 08 2011
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-06-08 15:21:47 -0400, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 This is not at all a feature of Objective-C. This was a workaround. 
 Tell  me, if inside a template you have an alias to a member function, 
 how can  I call that member function? This won't work:
 
 	void callMe(alias memberFunc)(Object o) {
 		o.memberFunc(); // won't work, Object has no member called  "memberFunc".
 	}

In this case, the alias points at A.func or something like that, no?

Exactly.
 So  you have enough information to figure out that the member function 
 is from  A?

Yes. (Although I'm not sure you can extract this info from the alias, the compiler has it, and I have it through other means, namely typeof(this)).
 That is my point, you almost never *don't know* where the member  
 function comes from.  And even if you don't, it's dangerous to simply  
 assume this.

The member function here is an alias, the compiler knows where this function comes from and can check whether the 'this' pointer is of the right type. It just won't let us call it because there's no syntax. That's the core of the problem. I worked around that by adding a non-virtual member function that just returns a delegate to the virtual one. Constructing the delegate manually is a workaround to call that non-virtual member. I can't call even a non-virtual member function without it because I mixin the same template many times within the same class, which creates ambiguous overloads for "resolveVirtualCall". Taking the address directly and assigning it to a delegate works because I'm not getting the symbol through the object but through the current scope which gives precedence to a function in the template scope. To make that clear, this works: private static R forwardVirtualCall(objc.runtime.id self, objc.runtime.SEL _cmd, A args) { R delegate(A) delegate() resolve; resolve.ptr = objc.msg.send!(void*)(self, objc.method.selector!("d_object")); resolve.funcptr = &resolveVirtualCall; return resolve()(args); } while this doesn't when mixing in the templates multiple times within a class: private static R forwardVirtualCall(objc.runtime.id self, objc.runtime.SEL _cmd, A args) { auto o = cast(typeof(this))objc.msg.send!(void*)(self, objc.method.selector!("d_object")); return o.resolveVirtualCall()(args); } It gives this error: /objc/bridge.d(253): Error: cocoa.foundation.date.NSDate.ObjcBindMethod!(opAdd,NSDate,"addTimeInterval:",double .resolveVirtualCall at /cocoa/foundation/date.d(245) conflicts with cocoa.foundation.date.NSDate.ObjcBindMethod!(isEqualToDate,bool,"isEqualToDate:",NSDate .resolveVirtualCall at /cocoa/foundation/date.d(245) I'm sorry if this wasn't clear the first time, I think it wasn't for me either. It's been a long time since I written or even used that code. To, to summarize: Calling a virtual function relied on defining and calling a non-virtual member. A non-virtual member which was ambiguous and could be called only through a manually-crafted delegate. Hence my need for a manually crafted delegate.
 In my proposal, I'd guess that &memberFunc would give you a  
 'delegate-function' pointer, which you could then cast o to the right 
 type  (assuming it is that type) and pass it into the function.
 
 i.e.:
 
 auto fptr = &memberFunc;
 fptr(cast(thisType!(fptr))o); // thisType gets the type of the 'this'  
 argument from the delegate-function pointer

That would probably work as it's just sugar for creating a delegate manually, with some added type safeties.
 Although even there it won't work very well if your member is a virtual 
  function. I needed to use an ever stranger workaround for that. Here's 
  the actual code from the Objective-C bridge (it's a template which be  
 mixed in the class):

This is an entirely different thing, a delegate removes the virtual-ness of the call. &A.func points to A's function, not to the virtual version (it can't possibly know that without an instance). Having a way to say "call vtable entry for A.func" for a specific object would be nice, but is not a delegate.

It'd be nice to have that, even if just as a library solution. Do we have a __traits to get the vtable offset of a function?
 All this is dependent on the idea that a delegate cannot be constructed 
   unless you have the original method (or a type-safe  
 'delegate-function'  such as int function(A this)).  I really think  
 that makes sense.

I won't disagree with anything you say, because I do agree. I know my use case is a fringe one, and I don't need it anymore so I don't care much. And it'd only need one small thing for it to work without all that cumbersome hack: o.memberFunc() // where methodFunc is an alias to a member of o

I'd much prefer memberFunc(o); This is of course for a delegate-function pointer, not for an alias. I'm not sure how an alias would work.

Agree. Also, an alias could work using the same syntax too if we had UFCS. :-) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Jun 2011 09:27:21 -0400, Daniel Murphy  
<yebblies nospamgmail.com> wrote:

 "Trass3r" <un known.com> wrote in message  
 news:op.vwq80v023ncmek enigma...
 ??
 Shouldn't this just return a delegate?

I don't think getting a delegate makes any sense without an instance. I'm talking about this case: class A { void func(); } void main() { // returns a nonsense function pointer auto f = &A.func; // returns a working delegate auto a = new A(); auto g = &a.func; }

The reason is to allow composition of delegates (not that I think this is a worthy reason): class A { void func(); void func2(); } void main() { auto f = &A.func2; auto a = new A(); auto g = &a.func; // delegate g.funcptr = f; g(); // calls a.func2() } I'd argue that a much more useful return type would be a delegate with the this pointer set to null, but then I don't know what funcptr would return. I almost think you need a separate type for it, which seems like a lot of effort for something that's hardly used. -Steve
Jun 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy  
<yebblies nospamgmail.com> wrote:

 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vwrgycgjeav7ka localhost.localdomain...
 The reason is to allow composition of delegates (not that I think this  
 is
 a worthy reason):

 class A
 {
    void func();
    void func2();
 }

 void main()
 {
    auto f = &A.func2;
    auto a = new A();
    auto g = &a.func; // delegate
    g.funcptr = f;
    g(); // calls a.func2()
 }

 I'd argue that a much more useful return type would be a delegate with  
 the
 this pointer set to null, but then I don't know what funcptr would
 return.  I almost think you need a separate type for it, which seems  
 like
 a lot of effort for something that's hardly used.

 -Steve

I can see this being useful, but I think it should be done by having delegate.funcptr be a void* and &ClassType.nonstaticmemberfunction return void*. The type safety provided by the current way it works is an illusion, as the following compiles: class A { void func() { do something using member variables or the vtable etc } } class B { void func() {} } void main() { auto b = new B(); auto dg = &b.func; dg.funcptr = &A.func; dg(); // Probably a segfault }

Yes, but removing type safety does not prevent that from happening, plus it allows something like this: class A { void func(); int func2(); } void main() { auto a = new A; auto dg = &a.func2(); dg.funcptr = &A.func; // works if dg.funcptr and &A.func are void*, but doesn't work today int x = dg(); // runs and returns garbage } I almost would prefer that hacking delegates would be illegal. Yes, you can get the function pointer and data pointer out of a delegate, but cannot set them. I can't think of any good use cases for them. I'm mixed on whether you should be able to get a member "function pointer". It would be nice to simply make it a normal function pointer that you can call with the appropriate type. BTW, if the calling convention is different, we may be able to allow it via creating a "this" function pointer: assert(is(typeof(&A.func2) == int function(A this))); Since this is a keyword, it can be interpreted as a different calling convention. -Steve
Jun 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Jun 2011 11:19:12 -0400, Daniel Murphy  
<yebblies nospamgmail.com> wrote:

 I can see the theoretical appeal of having member function pointers or  
 being
 able to call member functions as if they were globals, but I don't think  
 the
 practical uses really justify introducing new syntax or types or changing
 the ABI.  I also don't think any option which does any of those things  
 has a
 chance of getting incorporated into dmd.

The issue becomes, what is the type of dg.funcptr? And is it useable? I don't know if returning void * is the right answer, one of the main things I think would be required is: if(dg.funcptr is &A.func) {} Which is really all you can do with a void *, so it does satisfy most requirements. But I don't like that it can be passed into functions that for example, take a void *. It just seems odd that you don't get any type information. What I'd prefer is to have dg.funcptr return a new type like: int function(void this) which means, it cannot be called, because you don't know what type this is. However, accessing the function pointer from the originating type would return: int function(A this); I don't think we need to change the ABI. Calling the function with the given instance type would be the same as constructing the delegate and calling that delegate. As far as "new" syntax, you may have a point. I'll point out however that this is a seldom used "feature", and changing syntax would likely not affect very much code.
 If I can get some kind of consensus I'll try and patch dmd.
 I think the following covers most of your points, given that you can  
 still
 do the unsafe thing by casting:

 Make delegate.funcptr read only and return void*
 Make &ClassType.nonstaticmemberfunction return void*

Again, I think the read-only for funcptr is good, but void * seems too lax. But it's an acceptable update, better than nothing. -Steve
Jun 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Jun 2011 13:07:50 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2011-06-08 10:54:54 -0400, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:

 On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy   
 <yebblies nospamgmail.com> wrote:

 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message
 news:op.vwrgycgjeav7ka localhost.localdomain...
  The reason is to allow composition of delegates (not that I think  
 this  is
 a worthy reason):
  class A
 {
    void func();
    void func2();
 }
  void main()
 {
    auto f = &A.func2;
    auto a = new A();
    auto g = &a.func; // delegate
    g.funcptr = f;
    g(); // calls a.func2()
 }
  I'd argue that a much more useful return type would be a delegate  
 with  the
 this pointer set to null, but then I don't know what funcptr would
 return.  I almost think you need a separate type for it, which seems   
 like
 a lot of effort for something that's hardly used.
  -Steve

delegate.funcptr be a void* and &ClassType.nonstaticmemberfunction return void*. The type safety provided by the current way it works is an illusion, as the following compiles: class A { void func() { do something using member variables or the vtable etc } } class B { void func() {} } void main() { auto b = new B(); auto dg = &b.func; dg.funcptr = &A.func; dg(); // Probably a segfault }

plus it allows something like this: class A { void func(); int func2(); } void main() { auto a = new A; auto dg = &a.func2(); dg.funcptr = &A.func; // works if dg.funcptr and &A.func are void*, but doesn't work today int x = dg(); // runs and returns garbage } I almost would prefer that hacking delegates would be illegal. Yes, you can get the function pointer and data pointer out of a delegate, but cannot set them. I can't think of any good use cases for them.

I was "hacking delegates" a lot in the D/Objective-C bridge (before I decided to bring things directly in the compiler). To make it short, I needed to do that to call the appropriate D function from Objective-C stub method implementation.

The issue with hacking delegates I have is that almost certainly you know what the type of the function pointer is, which means you almost certainly have access to the member function for that type directly, it seems a very strange use case to be able to dynamically address the member functions of a class without knowing the type. When I first wrote the above reason, I tried to think of a compelling real example, I couldn't. Now, you are implementing a bridge to another language that supports a feature, which means you have to implement it. But how often is that feature used in that other language?
 BTW, if the calling convention is different, we may be able to allow it  
  via creating a "this" function pointer:
  assert(is(typeof(&A.func2) == int function(A this)));
  Since this is a keyword, it can be interpreted as a different calling   
 convention.

I was thinking about that too. Note that it forces int function(A this) to be implicitly castable to int function(void* this) when assigning to a delegate.

ATM, delegates and functions do not implicitly cast whatsoever. In fact, I would not want the above cast to succeed, what should be implicitly cast is a contravariant function. For example int function(Object this) should implicitly cast to int function(A this). Now, a delegate does not record its 'this' type, so getting the function pointer for the delegate should yield an uncallable function pointer. I proposed in another part of this thread the syntax: int function(void this); This at least gives you type information, but doesn't allow you to unsafely call it. If you wish to explicitly cast it to a viable function, you can. All this is dependent on the idea that a delegate cannot be constructed unless you have the original method (or a type-safe 'delegate-function' such as int function(A this)). I really think that makes sense. -Steve
Jun 08 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Jun 2011 14:13:46 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2011-06-08 13:29:27 -0400, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:

 On Wed, 08 Jun 2011 13:07:50 -0400, Michel Fortin   
 <michel.fortin michelf.com> wrote:

 On 2011-06-08 10:54:54 -0400, "Steven Schveighoffer"   
 <schveiguy yahoo.com> said:

 On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy    
 <yebblies nospamgmail.com> wrote:
   I almost would prefer that hacking delegates would be illegal.   
 Yes,  you  can get the function pointer and data pointer out of a  
 delegate,  but  cannot set them.  I can't think of any good use cases  
 for them.

I decided to bring things directly in the compiler). To make it short, I needed to do that to call the appropriate D function from Objective-C stub method implementation.

know what the type of the function pointer is, which means you almost certainly have access to the member function for that type directly, it seems a very strange use case to be able to dynamically address the member functions of a class without knowing the type. When I first wrote the above reason, I tried to think of a compelling real example, I couldn't. Now, you are implementing a bridge to another language that supports a feature, which means you have to implement it. But how often is that feature used in that other language?

This is not at all a feature of Objective-C. This was a workaround. Tell me, if inside a template you have an alias to a member function, how can I call that member function? This won't work: void callMe(alias memberFunc)(Object o) { o.memberFunc(); // won't work, Object has no member called "memberFunc". }

In this case, the alias points at A.func or something like that, no? So you have enough information to figure out that the member function is from A? That is my point, you almost never *don't know* where the member function comes from. And even if you don't, it's dangerous to simply assume this. In my proposal, I'd guess that &memberFunc would give you a 'delegate-function' pointer, which you could then cast o to the right type (assuming it is that type) and pass it into the function. i.e.: auto fptr = &memberFunc; fptr(cast(thisType!(fptr))o); // thisType gets the type of the 'this' argument from the delegate-function pointer
 Although even there it won't work very well if your member is a virtual  
 function. I needed to use an ever stranger workaround for that. Here's  
 the actual code from the Objective-C bridge (it's a template which be  
 mixed in the class):

This is an entirely different thing, a delegate removes the virtual-ness of the call. &A.func points to A's function, not to the virtual version (it can't possibly know that without an instance). Having a way to say "call vtable entry for A.func" for a specific object would be nice, but is not a delegate.
 All this is dependent on the idea that a delegate cannot be constructed  
  unless you have the original method (or a type-safe  
 'delegate-function'  such as int function(A this)).  I really think  
 that makes sense.

I won't disagree with anything you say, because I do agree. I know my use case is a fringe one, and I don't need it anymore so I don't care much. And it'd only need one small thing for it to work without all that cumbersome hack: o.memberFunc() // where methodFunc is an alias to a member of o

I'd much prefer memberFunc(o); This is of course for a delegate-function pointer, not for an alias. I'm not sure how an alias would work. -Steve
Jun 08 2011
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Daniel Murphy Wrote:

 Currently, this compiles:
 
 class A
 {
     void func() {}
 }
 
 void main()
 {
   auto p = &A.func;
 }
 
 In this case, typeof(p) is void function().

Shouldn't it be void function(A)? As long as the ABI supports it, that would make the most sense to me... As I understand it, the this pointer is just a hidden parameter.
Jun 08 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jason House" <jason.james.house gmail.com> wrote in message 
news:isntm4$2ull$1 digitalmars.com...
 Shouldn't it be void function(A)? As long as the ABI supports it, that 
 would make the most sense to me... As I understand it, the this pointer is 
 just a hidden parameter.

parameter, so that kind of conversion would only work for a subset of functions. eg. class A { int funcA(int); } is equivalent to: int function(int, A) and struct S { int a, b, c; } class A { S funcA(int); } is equivalent to: void function(int, S*, A)
Jun 08 2011
prev sibling next sibling parent reply David Nadlinger <see klickverbot.at> writes:
Oh wow, my previous comment was total nonsense, I confused .func with 
the delegate .funcptr property…

The bugs probably comes from the delegate .funcptr property being a 
function pointer of the same signature as the delegate type itself, 
which doesn't make too much sense: 
http://d.puremagic.com/issues/show_bug.cgi?id=2672. Presumably because 
of this, &A.func also has the same type so things match up.

However, as not every delegate can be called as a function because of 
ABI reasons (think about the hidden struct return pointer), changing the 
type of delegate.funcptr to void* as well might be the better solution.

David


On 6/8/11 10:00 AM, Daniel Murphy wrote:
 Currently, this compiles:

 class A
 {
      void func() {}
 }

 void main()
 {
    auto p =&A.func;
 }

 In this case, typeof(p) is void function().
 Calling one of these pointers, of course, can easily give you a segfault as
 it completely ignores the this pointer.
 I didn't even realize you could do this until I saw
 http://d.puremagic.com/issues/show_bug.cgi?id=5986

 I understand that it could be useful to have a way to get the address of a
 non-static member function, but I doubt returning a malformed function
 pointer is really useful.

 Does anybody think changing&ClassType.nonStaticMember to return void* would
 be a bad idea?

Jun 08 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"David Nadlinger" <see klickverbot.at> wrote in message 
news:iso2fc$6a2$1 digitalmars.com...
 Oh wow, my previous comment was total nonsense, I confused .func with the 
 delegate .funcptr property.

 The bugs probably comes from the delegate .funcptr property being a 
 function pointer of the same signature as the delegate type itself, which 
 doesn't make too much sense: 
 http://d.puremagic.com/issues/show_bug.cgi?id=2672. Presumably because of 
 this, &A.func also has the same type so things match up.

 However, as not every delegate can be called as a function because of ABI 
 reasons (think about the hidden struct return pointer), changing the type 
 of delegate.funcptr to void* as well might be the better solution.

 David

I think the botched type comes from the compiler's implementation - function types have no idea wheather they have a this parameter or not! I'm currently thinking changing &ClassType.nonstaticmemberfunction and delegate.funcptr to return void*, and making delegate.funcptr read-only should smooth off this nasty corner quite nicely.
Jun 08 2011
prev sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
Turned out it was even easier to do than I expected:

https://github.com/yebblies/dmd/commit/ed7a499d689940fd21d23bb658e97b1024a7d6be

I'm not sure if delegate.funcptr should return a void* lvalue or a 
const(void)* rvalue though.  The latter would allow you to cast away const 
and mess with it. 
Jun 08 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Daniel Murphy" <yebblies nospamgmail.com> wrote in message 
news:isofvu$13tv$1 digitalmars.com...
 Turned out it was even easier to do than I expected:

 https://github.com/yebblies/dmd/commit/ed7a499d689940fd21d23bb658e97b1024a7d6be

 I'm not sure if delegate.funcptr should return a void* lvalue or a 
 const(void)* rvalue though.  The latter would allow you to cast away const 
 and mess with it.

Jun 08 2011