Pointers to non-static member functions!

Steven Schveighoffer schveiguy at yahoo.com
Wed Jun 8 10:29:27 PDT 2011


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

> On 2011-06-08 10:54:54 -0400, "Steven Schveighoffer"  
> <schveiguy at yahoo.com> said:
>
>> On Wed, 08 Jun 2011 10:40:48 -0400, Daniel Murphy   
>> <yebblies at nospamgmail.com> wrote:
>>
>>> "Steven Schveighoffer" <schveiguy at yahoo.com> wrote in message
>>> news:op.vwrgycgjeav7ka at 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.

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


More information about the Digitalmars-d mailing list