Pointers to non-static member functions!

Michel Fortin michel.fortin at michelf.com
Wed Jun 8 13:41:17 PDT 2011


On 2011-06-08 15:21:47 -0400, "Steven Schveighoffer" 
<schveiguy at 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 at michelf.com
http://michelf.com/



More information about the Digitalmars-d mailing list