June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 2013-06-08 01:21, Manu wrote: > So from my dconf talk, I detailed a nasty hack to handle member function > pointers in D. > My approach is not portable, so I'd like to see an expression formalised > in D, so this sort of interaction with C++ is possible, and also it may > be useful in D code directly. > > I'm thinking something like this... Keen to hear thoughts. > > My approach was this: > void function(T _this, ...args...); > > Explicit 'this' pointer; only works with ABI's that pass 'this' as the > first integer argument. > > What I suggest is: > void function(T this, ...args...); > > Note, I use keyword 'this' as the first argument. This is the key that > distinguishes the expression as a member-function pointer rather than a > typical function pointer. Calls through this function pointer would know > to use the method calling convention rather than the static function > calling convention. > > For 'extern(C++) void function(T this)', that would be to use the C++ > 'thiscall' convention. > > I think this makes good sense, because other than the choice of calling > convention, it really is just a 'function' in every other way. Can't we just say that a delegate declared as extern(C++) is a member function? Or do you want to use member functions without connecting to C++ as well? -- /Jacob Carlborg |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg Attachments:
| On 10 June 2013 16:50, Jacob Carlborg <doob@me.com> wrote:
> On 2013-06-08 01:21, Manu wrote:
>
>> So from my dconf talk, I detailed a nasty hack to handle member function
>> pointers in D.
>> My approach is not portable, so I'd like to see an expression formalised
>> in D, so this sort of interaction with C++ is possible, and also it may
>> be useful in D code directly.
>>
>> I'm thinking something like this... Keen to hear thoughts.
>>
>> My approach was this:
>> void function(T _this, ...args...);
>>
>> Explicit 'this' pointer; only works with ABI's that pass 'this' as the first integer argument.
>>
>> What I suggest is:
>> void function(T this, ...args...);
>>
>> Note, I use keyword 'this' as the first argument. This is the key that distinguishes the expression as a member-function pointer rather than a typical function pointer. Calls through this function pointer would know to use the method calling convention rather than the static function calling convention.
>>
>> For 'extern(C++) void function(T this)', that would be to use the C++
>> 'thiscall' convention.
>>
>> I think this makes good sense, because other than the choice of calling convention, it really is just a 'function' in every other way.
>>
>
> Can't we just say that a delegate declared as extern(C++) is a member
> function?
That seems pretty awkward to me. Basically a hack.
A function pointer is not a delegate, so I don't see why that should be
used to describe one.
Also, extern(C++) delegates are useful too in their own right
Or do you want to use member functions without connecting to C++ as well?
I haven't needed to yet... but that doesn't mean it might not be useful. It would probably be used in D for tight binding with other systems. AngelScript binds to native code with member function pointers... just off the top of my head.
|
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 2013-06-10 09:23, Manu wrote: > That seems pretty awkward to me. Basically a hack. > A function pointer is not a delegate, so I don't see why that should be > used to describe one. It depends on how you look at it. In D a delegate is a function pointer with a context pointer. In C++ a pointer to a member function is basically the same, the context pointer is just passed separately. > Also, extern(C++) delegates are useful too in their own right To do what? As far as I know C++ doesn't have anything corresponding to a D delegate. > I haven't needed to yet... but that doesn't mean it might not be useful. > It would probably be used in D for tight binding with other systems. > AngelScript binds to native code with member function pointers... just > off the top of my head. Actually I don't see why you can't use a delegate for this. The only difference is that it won't be virtual. -- /Jacob Carlborg |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg Attachments:
| On 10 June 2013 18:04, Jacob Carlborg <doob@me.com> wrote: > On 2013-06-10 09:23, Manu wrote: > > That seems pretty awkward to me. Basically a hack. >> A function pointer is not a delegate, so I don't see why that should be used to describe one. >> > > It depends on how you look at it. In D a delegate is a function pointer with a context pointer. In C++ a pointer to a member function is basically the same, the context pointer is just passed separately. A function pointer is a pointer. A delegate is a pointer to a function and a context pointer, ie, 2 pointers. A pointer to a method is just a pointer to a function, but it's a special function which receives a 'this' argument with a special calling convention. It's definitely useful to be able to express a 'thiscall' function pointer. Also, extern(C++) delegates are useful too in their own right >> > > To do what? As far as I know C++ doesn't have anything corresponding to a D delegate. C++ has FastDelegate, which I use to interact with D delegates all the time! ;) extern(C++) delegate is required to specify the appropriate calling convention, otherwise it's just a delegate like usual. I haven't needed to yet... but that doesn't mean it might not be useful. >> It would probably be used in D for tight binding with other systems. AngelScript binds to native code with member function pointers... just off the top of my head. >> > > Actually I don't see why you can't use a delegate for this. The only difference is that it won't be virtual. I'm just trying to show that sometimes you don't want a delegate, you just want a function pointer. delegate's contain the function pointer I'm after, so I can access it indirectly, but it's just not so useful. It's not typed (is void*), and you can't call through it. |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 2013-06-10 11:45, Manu wrote: > A function pointer is a pointer. A delegate is a pointer to a function > and a context pointer, ie, 2 pointers. > A pointer to a method is just a pointer to a function, but it's a > special function which receives a 'this' argument with a special calling > convention. > It's definitely useful to be able to express a 'thiscall' function pointer. It's not very useful without the context pointer, i.e. "this". > Also, extern(C++) delegates are useful too in their own right > > > To do what? As far as I know C++ doesn't have anything corresponding > to a D delegate. > > > C++ has FastDelegate, which I use to interact with D delegates all the > time! ;) I didn't know about that. Is that something that is in the language or standard library? > extern(C++) delegate is required to specify the appropriate calling > convention, otherwise it's just a delegate like usual. I see. > I'm just trying to show that sometimes you don't want a delegate, you > just want a function pointer. Then use a function pointer. > delegate's contain the function pointer I'm after, so I can access it > indirectly, but it's just not so useful. It's not typed (is void*), and > you can't call through it. The function pointer of a delegate is typed, it's the context pointer that is void*. Sorry, I'm just trying to understand what you're doing, what problems you have. You can compose and decompose delegates using its built-in properties "ptr" and "funcptr". You can do something like: class Foo { int i; void a () { writeln("Foo.a i=", i); } void b () { writeln("Foo.b i=", i); } } void main () { auto f1 = new Foo; f1.i = 3; auto dg = &f1.a; dg(); auto f2 = new Foo; f2.i = 4; dg.ptr = cast(void*) f2; dg(); dg.funcptr = &Foo.b; dg(); } The only thing that doesn't work with the above is if I change the context pointer to a subclass of Foo which overrides the method I want to call. It will still call the method in Foo unless I change "funcptr". -- /Jacob Carlborg |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On 2013-06-10 08:04:43 +0000, Jacob Carlborg <doob@me.com> said: > On 2013-06-10 09:23, Manu wrote: > >> That seems pretty awkward to me. Basically a hack. >> A function pointer is not a delegate, so I don't see why that should be >> used to describe one. > > It depends on how you look at it. In D a delegate is a function pointer with a context pointer. In C++ a pointer to a member function is basically the same, the context pointer is just passed separately. But a true member function pointer is also parametrized on the type of this, unlike a delegate, letting you change the object pointer in a type-safe manner. (And implementation-wise, C++ function pointers can be really complicated beasts in order to support virtual calling and multiple/virtual inheritance. sizeof can even change depending on the type of "this". That's not what you want in D.) >> I haven't needed to yet... but that doesn't mean it might not be useful. >> It would probably be used in D for tight binding with other systems. >> AngelScript binds to native code with member function pointers... just >> off the top of my head. > > Actually I don't see why you can't use a delegate for this. The only difference is that it won't be virtual. Type-safety. I mean, you can do this if you want: auto funcptr = &Object.toString; auto object = new Object; // now call our function using object string delegate() deleg; deleg.ptr = cast(void*)object; deleg.funcptr = funcptr; but this is not type-safe: the funcptr type ("string function()") is actually wrong (it'll only work if called from a delegate) and the object pointer the in the delegate is a void*. All Manu is asking is that funcptr is of a correct type so you can call it directly by supplying "this" as an argument, like this: funcptr(object); The problem is that this "correct type" for the function pointer does not exist currently. Calling a member function uses a different ABI, so the type needs to know somehow its a pointer to a member function (and that its first parameter is "this"), otherwise the generated code at the call site will be all wrong. -- Michel Fortin michel.fortin@michelf.ca http://michelf.ca/ |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg Attachments:
| On 10 June 2013 21:35, Jacob Carlborg <doob@me.com> wrote: > On 2013-06-10 11:45, Manu wrote: > > A function pointer is a pointer. A delegate is a pointer to a function >> and a context pointer, ie, 2 pointers. >> A pointer to a method is just a pointer to a function, but it's a >> special function which receives a 'this' argument with a special calling >> convention. >> It's definitely useful to be able to express a 'thiscall' function >> pointer. >> > > It's not very useful without the context pointer, i.e. "this". > You supply 'this' at the time of calling. Read my OP. Also, extern(C++) delegates are useful too in their own right >> >> >> To do what? As far as I know C++ doesn't have anything corresponding >> to a D delegate. >> >> >> C++ has FastDelegate, which I use to interact with D delegates all the time! ;) >> > > I didn't know about that. Is that something that is in the language or standard library? It's Don's work of art. It's also how I came to find out about D in the first place ;) extern(C++) delegate is required to specify the appropriate calling >> convention, otherwise it's just a delegate like usual. >> > > I see. > > > I'm just trying to show that sometimes you don't want a delegate, you >> just want a function pointer. >> > > Then use a function pointer. There's no way to specify to use the 'thiscall' calling convention. What I propose is a syntax that would describe a member function pointer, and imply the appropriate calling convention. delegate's contain the function pointer I'm after, so I can access it >> indirectly, but it's just not so useful. It's not typed (is void*), and >> you can't call through it. >> > > The function pointer of a delegate is typed, it's the context pointer that is void*. > > Sorry, I'm just trying to understand what you're doing, what problems you have. You can compose and decompose delegates using its built-in properties "ptr" and "funcptr". > > You can do something like: > > class Foo > { > int i; > > void a () { writeln("Foo.a i=", i); } > void b () { writeln("Foo.b i=", i); } > } > > void main () > { > auto f1 = new Foo; > f1.i = 3; > auto dg = &f1.a; > dg(); > > auto f2 = new Foo; > f2.i = 4; > dg.ptr = cast(void*) f2; > dg(); > > dg.funcptr = &Foo.b; > dg(); > } > > The only thing that doesn't work with the above is if I change the context pointer to a subclass of Foo which overrides the method I want to call. It will still call the method in Foo unless I change "funcptr". I wouldn't say that doesn't work, I'd say that works perfectly. A delegate is just a 'this' and function pair. If you change 'this', there's no reason the function should change. funcptr pretends to be typed, but the type is just wrong. In your example, the type is 'void function()', it should be 'void function(Foo this)'. So it's actually a lie. You can't call it. I'm not sure why it's typed at all... just a crash waiting to happen. So what I'm suggesting is a syntax to express a member function pointer, and then it could be properly typed. |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 2013-06-10 14:36, Manu wrote: > You supply 'this' at the time of calling. Read my OP. Yes, exactly. It needs "this". It's the same thing as a delegate. It's just that with the delegate the context pointer and function pointer is combined. A function pointer (member or free) is useless if it's not called. > It's Don's work of art. It's also how I came to find out about D in the > first place ;) I see. > There's no way to specify to use the 'thiscall' calling convention. > What I propose is a syntax that would describe a member function > pointer, and imply the appropriate calling convention. Right. I suggested a different syntax, but you want to reserve that syntax for something that match a library implementation, that's not even in the standard. It's like saying I want int[] to match MyIntArray implemented in C++. > funcptr pretends to be typed, but the type is just wrong. In your > example, the type is 'void function()', it should be 'void function(Foo > this)'. "void function()" is part of the complete type. It becomes complete with the context pointer. > So it's actually a lie. You can't call it. I'm not sure why it's typed > at all... just a crash waiting to happen. You can put a free function in a delegate and call it through the delegate. I guess you don't want that to be possible either. > So what I'm suggesting is a syntax to express a member function pointer, > and then it could be properly typed. I don't think there's anything wrong with supporting C++ member function pointers but I don't think we need to add new syntax for it. -- /Jacob Carlborg |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | On 2013-06-10 14:32, Michel Fortin wrote: > Type-safety. I mean, you can do this if you want: > > auto funcptr = &Object.toString; > auto object = new Object; > > // now call our function using object > string delegate() deleg; > deleg.ptr = cast(void*)object; > deleg.funcptr = funcptr; > > but this is not type-safe: the funcptr type ("string function()") is > actually wrong (it'll only work if called from a delegate) and the > object pointer the in the delegate is a void*. All Manu is asking is > that funcptr is of a correct type so you can call it directly by > supplying "this" as an argument, like this: > > funcptr(object); > > The problem is that this "correct type" for the function pointer does > not exist currently. Calling a member function uses a different ABI, so > the type needs to know somehow its a pointer to a member function (and > that its first parameter is "this"), otherwise the generated code at the > call site will be all wrong. Then he's asking for (more) type safe delegates and support for C++ member function pointers. -- /Jacob Carlborg |
June 10, 2013 Re: Member function pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | 08-Jun-2013 03:21, Manu пишет: > So from my dconf talk, I detailed a nasty hack to handle member function > pointers in D. > My approach is not portable, so I'd like to see an expression formalised > in D, so this sort of interaction with C++ is possible, and also it may > be useful in D code directly. > > I'm thinking something like this... Keen to hear thoughts. > > My approach was this: > void function(T _this, ...args...); > > Explicit 'this' pointer; only works with ABI's that pass 'this' as the > first integer argument. I decided to see how convenient can be a solution to auto-generate a thunk function that has exactly this signutre. In ABIs where this is passed as first parameters that shouldn't be much of overhead. Here is my first try, it needs to handle overload sets but that could be added. Second point is perfect forwarding (there is forward in std.typecons, avoided for now). It may as well depend on compiler bugs but it looks nice and clean :) module mem_fun; import std.traits, std.stdio; template memThunk(string call, T, U...) if(is(T == class)) { auto memThunk(T self, U args) { return mixin("self." ~ call~"(args)"); } } struct memberFunc(T) if(is(T == class)) { static @property auto opDispatch(string fn)() { alias FnType = typeof(mixin("T."~fn)); return &memThunk!(fn, T, ParameterTypeTuple!FnType); } } class A{ void foo(int k) { writefln("Quack %d!\n", k); } } unittest { void function (A, int) fun = memberFunc!A.foo; A a = new A(); fun(a, 45); //prints Quack 45! } P.S. Having a way to express this-call calling convention explicitly could be very useful still especially taking into account recent enhancements to the extern(C++) support. -- Dmitry Olshansky |
Copyright © 1999-2021 by the D Language Foundation