Re: Member function pointers
On Friday, 11 September 2015 at 00:37:35 UTC, data man wrote: On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: ... Heh. My fault. Fixed (though it'll stick for that post in some views). Correct a "D-Runtime" topic, please. It is not updated. Not sure what you mean, please clarify. If it's not related to this thread, please file bugs on https://github.com/CyberShadow/DFeed/issues to avoid off-topic discussion.
Re: Member function pointers
On Thursday, 10 September 2015 at 01:52:17 UTC, digitalmars.D wrote: On 10 September 2015 at 04:55, Walter Bright via Digitalmars-dwrote: On 6/10/2013 7:33 AM, Manu wrote: [...] Sorry to say, your n.g. poster is back to its old tricks :-) We've resolved this issue since 6/10/2013 no? ;) In the web forum, this post shows up as having author "digitalmars.D", not even "Manu via Digitalmars-d" like your posts normally do and definitely not "Manu" like it should. CyberShadow?
Re: Member function pointers
On Thursday, 10 September 2015 at 16:18:13 UTC, John Colvin wrote: On Thursday, 10 September 2015 at 01:52:17 UTC, digitalmars.D wrote: On 10 September 2015 at 04:55, Walter Bright via Digitalmars-dwrote: On 6/10/2013 7:33 AM, Manu wrote: [...] Sorry to say, your n.g. poster is back to its old tricks :-) We've resolved this issue since 6/10/2013 no? ;) In the web forum, this post shows up as having author "digitalmars.D", not even "Manu via Digitalmars-d" like your posts normally do and definitely not "Manu" like it should. CyberShadow? Heh. My fault. Fixed (though it'll stick for that post in some views).
Re: Member function pointers
On Thursday, 10 September 2015 at 21:29:15 UTC, Vladimir Panteleev wrote: Doesn't happen here, so that's something local to you, almost surely unrelated to the above. Try clearing your cookies. Yes, it was caused by cookies, but it wasn't local since it returned a HTTP status 500. It happend on the web server.
Re: Member function pointers
On Thursday, 10 September 2015 at 21:24:17 UTC, Ola Fosheim Grøstad wrote: On Thursday, 10 September 2015 at 20:15:15 UTC, Vladimir Panteleev wrote: On Thursday, 10 September 2015 at 19:40:02 UTC, Ola Fosheim Grøstad wrote: On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: Heh. My fault. Fixed (though it'll stick for that post in some views). Now the main index says: "Unexpected end of input when converting from type string to type long". Doesn't happen here, so that's something local to you, almost surely unrelated to the above. Try clearing your cookies. Request URL:http://forum.dlang.org/ Request Method:GET Status Code:500 Internal Server Error Doesn't happen here, so that's something local to you, almost surely unrelated to the above. Try clearing your cookies.
Re: Member function pointers
On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: ... Heh. My fault. Fixed (though it'll stick for that post in some views). Correct a "D-Runtime" topic, please. It is not updated.
Re: Member function pointers
On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: Heh. My fault. Fixed (though it'll stick for that post in some views). Now the main index says: "Unexpected end of input when converting from type string to type long".
Re: Member function pointers
On Thursday, 10 September 2015 at 19:40:02 UTC, Ola Fosheim Grøstad wrote: On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: Heh. My fault. Fixed (though it'll stick for that post in some views). Now the main index says: "Unexpected end of input when converting from type string to type long". Doesn't happen here, so that's something local to you, almost surely unrelated to the above. Try clearing your cookies.
Re: Member function pointers
On Thursday, 10 September 2015 at 20:15:15 UTC, Vladimir Panteleev wrote: On Thursday, 10 September 2015 at 19:40:02 UTC, Ola Fosheim Grøstad wrote: On Thursday, 10 September 2015 at 16:24:52 UTC, Vladimir Panteleev wrote: Heh. My fault. Fixed (though it'll stick for that post in some views). Now the main index says: "Unexpected end of input when converting from type string to type long". Doesn't happen here, so that's something local to you, almost surely unrelated to the above. Try clearing your cookies. Request URL:http://forum.dlang.org/ Request Method:GET Status Code:500 Internal Server Error
Re: Member function pointers
On Wednesday, 9 September 2015 at 18:33:41 UTC, Prudence wrote: On Tuesday, 27 May 2014 at 12:21:40 UTC, d coder wrote: [...] What's the current state of this? I'm in need of such behavior for win32 interop. I'm thinking that one can make the above code more general by using it in a mixin and automatically generating the funcptr signature: import std.stdio; import std.concurrency; extern (C) int getch(); import std.string; template FancyDelegate(O, D) { const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function("~O.stringof~",").replace(",)", ")")~" funcptr; } }"; //const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function(")~" funcptr; } }"; } class X { public int z = 2; public void foo(int x) { //writeln(this.z*x); writeln(x); } } void delegate(int) dg; mixin(FancyDelegate!(X, typeof(dg))); void main() { auto xX = new X(); XDelegate x; x.dg = //x.dg(3); x.ptr = x.funcptr(xX, 5); //x.funcptr(5); getch(); } Unfortunately this fails when entering the function. I've tried various things(passing , etc..., passing nothing(the comments, etc.) I thought a delegate, when called, was called like a member function? It seems that a delegate is some magic black box that we can't emulate in any way shape or form due to the calling conventions used? struct S { void fun() { writeln("fun" ); } } class C { void fun() { writeln("fun" ); } } void main(string[] args) { S s; void delegate() fn1 = fn1(); C c = new C(); void delegate() fn2 = fn2(); void delegate() fn3; fn3.ptr = cast(void*) fn3.funcptr = fn3(); void delegate() fn4; fn4.ptr = cast(void*)c; fn4.funcptr = fn4(); }
Re: Member function pointers
On 10 September 2015 at 04:55, Walter Bright via Digitalmars-dwrote: > On 6/10/2013 7:33 AM, Manu wrote: >> >> [...] > > > Sorry to say, your n.g. poster is back to its old tricks :-) We've resolved this issue since 6/10/2013 no? ;)
Re: Member function pointers
On 9/9/2015 6:52 PM, Manu via Digitalmars-d wrote: We've resolved this issue since 6/10/2013 no? ;) :-)
Re: Member function pointers
On 6/7/2013 4:21 PM, Manu wrote: So from my dconf talk, I detailed a nasty hack to handle member function pointers in D. https://www.digitalmars.com/articles/b68.html
Re: Member function pointers
On 6/10/2013 7:33 AM, Manu wrote: [...] Sorry to say, your n.g. poster is back to its old tricks :-)
Re: Member function pointers
On Tuesday, 27 May 2014 at 12:21:40 UTC, d coder wrote: https://github.com/D-Programming-Language/dmd/pull/3181 Daniel asked me to use this. And it works. Use something like: union U { void delegate(int) dg; struct { void* ptr; void function(int) funcptr; } } U u; u.dg = dg; u.funcptr = ...; u.ptr = ...; Regards - Puneet What's the current state of this? I'm in need of such behavior for win32 interop. I'm thinking that one can make the above code more general by using it in a mixin and automatically generating the funcptr signature: import std.stdio; import std.concurrency; extern (C) int getch(); import std.string; template FancyDelegate(O, D) { const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function("~O.stringof~",").replace(",)", ")")~" funcptr; } }"; //const char[] FancyDelegate = "union "~O.stringof~"Delegate { "~D.stringof~" dg; struct { "~O.stringof~"* ptr; "~D.stringof.replace("delegate(", "function(")~" funcptr; } }"; } class X { public int z = 2; public void foo(int x) { //writeln(this.z*x); writeln(x); } } void delegate(int) dg; mixin(FancyDelegate!(X, typeof(dg))); void main() { auto xX = new X(); XDelegate x; x.dg = //x.dg(3); x.ptr = x.funcptr(xX, 5); //x.funcptr(5); getch(); } Unfortunately this fails when entering the function. I've tried various things(passing , etc..., passing nothing(the comments, etc.) I thought a delegate, when called, was called like a member function? It seems that a delegate is some magic black box that we can't emulate in any way shape or form due to the calling conventions used?
Re: Member function pointers
On Wednesday, 9 September 2015 at 20:18:06 UTC, Freddy wrote: enum MemberFunc(alias Type, string member) = (ref Type self, Parameters!(__traits(getMember, Type, member)) args) => mixin(q{self.} ~ member ~ q{(args)}); Whoops the alias wasn't needed enum MemberFunc(Type, string member) = (ref Type self, Parameters!(__traits(getMember, Type, member)) args) => mixin(q{self.} ~ member ~ q{(args)});
Re: Member function pointers
On Wednesday, 9 September 2015 at 18:55:18 UTC, Walter Bright wrote: On 6/10/2013 7:33 AM, Manu wrote: [...] Sorry to say, your n.g. poster is back to its old tricks :-) On 6/10/2013 That was 2 years ago.
Re: Member function pointers
On Wednesday, 9 September 2015 at 18:50:45 UTC, Walter Bright wrote: On 6/7/2013 4:21 PM, Manu wrote: So from my dconf talk, I detailed a nasty hack to handle member function pointers in D. https://www.digitalmars.com/articles/b68.html Here's on automatic version import std.traits : Parameters; enum MemberFunc(alias Type, string member) = (ref Type self, Parameters!(__traits(getMember, Type, member)) args) => mixin(q{self.} ~ member ~ q{(args)}); unittest { static struct A { bool test; void b(int arg) { test = arg == 4; } } A a; auto func = MemberFunc!(A, "b"); func(a,4); assert(a.test); }
Re: Member function pointers
On 9/9/2015 1:17 PM, Freddy wrote: On Wednesday, 9 September 2015 at 18:55:18 UTC, Walter Bright wrote: On 6/10/2013 7:33 AM, Manu wrote: [...] Sorry to say, your n.g. poster is back to its old tricks :-) On 6/10/2013 That was 2 years ago. Woops! I didn't notice. My reader sorts things based on the date of the last post.
Re: Member function pointers
On Mon, Jun 10, 2013 at 10:13 PM, Jacob Carlborg d...@me.com wrote: On 2013-06-10 18:34, Manu wrote: On 11 June 2013 02:26, Jacob Carlborg d...@me.com mailto:d...@me.com wrote: On 2013-06-10 17:40, David Nadlinger wrote: Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- Why is this better than a delegate? It's not 'better', it's different. class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; void delegate () dg; dg.funcptr = memberFun; dg.ptr = cast(void*) a; dg(); The details can be hidden in a function call. Sure, a delegate could be type safe but still don't see the point. -- /Jacob Carlborg Greetings Apologies for bringing up this year old thread. With https://github.com/D-Programming-Language/dmd/pull/3181 getting merged, it is no longer feasible to directly assign dg.funcptr (which is not an lvalue now). The problem is that the code suggested by David also does not work. Is there an alternative? Regards - Puneet
Re: Member function pointers
https://github.com/D-Programming-Language/dmd/pull/3181 Daniel asked me to use this. And it works. Use something like: union U { void delegate(int) dg; struct { void* ptr; void function(int) funcptr; } } U u; u.dg = dg; u.funcptr = ...; u.ptr = ...; Regards - Puneet
Re: Member function pointers
Michel Fortin michel.for...@michelf.ca wrote in message news:kp4nr0$q71$1...@digitalmars.com... I just find it sad that we have to use a different calling convention for member functions. I mean, it'd be much more elegant be if a member function could simply be called from a void function(Object) by supplying this as the first argument? Wouldn't it be better to adapt the ABI to fit the language rather than adapt the language to fit the ABI? For D, yes, and it would be awesome. For everything else, never ever ever.
Re: Member function pointers
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
Re: Member function pointers
On 10 June 2013 16:50, Jacob Carlborg d...@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.
Re: Member function pointers
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
Re: Member function pointers
On 10 June 2013 18:04, Jacob Carlborg d...@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.
Re: Member function pointers
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
Re: Member function pointers
On 2013-06-10 08:04:43 +, Jacob Carlborg d...@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.for...@michelf.ca http://michelf.ca/
Re: Member function pointers
On 10 June 2013 21:35, Jacob Carlborg d...@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.
Re: Member function pointers
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
Re: Member function pointers
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
Re: Member function pointers
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
Re: Member function pointers
On Monday, 10 June 2013 at 12:53:34 UTC, Jacob Carlborg wrote: On 2013-06-10 14:36, Manu wrote: 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. I wouldn't say so. The fact that you pass context has nothing to do with determining type. For example, you can pass A class instead of B to B method, but B method would still keep its original type. So yes, there is a type problem in language when function taking some parameter is declared as having no such parameter. This is a serious hole in type system.
Re: Member function pointers
On 10 June 2013 22:53, Jacob Carlborg d...@me.com wrote: 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++. No, I'm not talking about delegates. I'm not talking about FastDelegate (that was an aside when you commented that C++ has no concept of delegate). I'm just talking about function pointers. Not sure where you get this analogy from? 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. The context pointer type is not present in the type. So the function can't be used/called. It also doesn't know how to call it. What's the calling convention for 'void function()'? cdecl? 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. A free function? Like a static function? You can assign it, but it'll crash. Free functions are cdecl, methods are thiscall. If you know the ABI and it receives 'this' as the first integer argument, you can fabricate a compatible signature and it won't crash, but it's not portable. This is my whole point about the type-safety. If we create an expression to describe a method pointer, then we can actually do it safely and portably. 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. I'm not suggesting supporting 'C++ member function pointers', they are completely bat-shit crazy. I'm suggesting a distinctly D way. They will be useful when interfacing C++, and also on their own, and unlike C++, they won't be totally mental.
Re: Member function pointers
On 10 June 2013 22:56, Jacob Carlborg d...@me.com wrote: 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. I'm really not asking for delegates (although they could become more typesafe given my suggestion), just a member function pointer. And not C++ style as you say, my suggestion is much simpler than that, and would fit nicely in D.
Re: Member function pointers
On Friday, 7 June 2013 at 23:22:03 UTC, Manu wrote: I think this makes good sense, because other than the choice of calling convention, it really is just a 'function' in every other way. Another less intrusive option would be to just add extern(CppThisCall) and extern(DThisCall) or something along the lines, which would be specified to pass the first parameter as if it was a this pointer. David
Re: Member function pointers
On Monday, 10 June 2013 at 13:45:37 UTC, Manu wrote: What's the calling convention for 'void function()'? cdecl? Walter's very own calling convention. It is supposed to match cdecl everywhere but x86, but has the argument order reversed. On x86, it's a custom one that's similar to stdcall in some ways. David
Re: Member function pointers
On 10 June 2013 23:49, David Nadlinger c...@klickverbot.at wrote: On Monday, 10 June 2013 at 13:45:37 UTC, Manu wrote: What's the calling convention for 'void function()'? cdecl? Walter's very own calling convention. It is supposed to match cdecl everywhere but x86, but has the argument order reversed. On x86, it's a custom one that's similar to stdcall in some ways. Indeed. I presume 'extern(C) void function()' is cdecl though? Likewise 'extern(C++) void function(T this)' would be 'thiscall', and 'void function(T this)' would be whatever D's method calling convention happens to be.
Re: Member function pointers
On 10 June 2013 23:46, David Nadlinger c...@klickverbot.at wrote: On Friday, 7 June 2013 at 23:22:03 UTC, Manu wrote: I think this makes good sense, because other than the choice of calling convention, it really is just a 'function' in every other way. Another less intrusive option would be to just add extern(CppThisCall) and extern(DThisCall) or something along the lines, which would be specified to pass the first parameter as if it was a this pointer. That would also do the business. Do you think that's less intrusive? It feels a little hacky though. 'DThisCall' isn't really 'extern' so to speak. I like my suggestion a lot more. Little details like, what would you name the 'this' argument? You'll end up with conventions like 'void function(T _this)', and that's a bit untrue because there isn't an argument named '_this', it's called 'this' inside the method.
Re: Member function pointers
On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote: On 10 June 2013 23:46, David Nadlinger c...@klickverbot.at Another less intrusive option would be to just add extern(CppThisCall) and extern(DThisCall) or something along the lines, which would be specified to pass the first parameter as if it was a this pointer. That would also do the business. Do you think that's less intrusive? Less intrusive in the way that it is a minimal addition to the language itself (we already have several calling conventions), whereas your suggestion would require adding a special case to the grammar. That's not to say I don't like your proposal, though. I just wanted to put the option on the table to be sure we are getting somewhere with this, even if some people might be opposed to the grammar change. This issue has been bugging me for quite some time as well. It feels a little hacky though. 'DThisCall' isn't really 'extern' so to speak. extern(D) exists today – extern(xyz) should really be called abi(xyz), callingconv(xyz) or something like that instead. David
Re: Member function pointers
On 11 June 2013 00:28, Michel Fortin michel.for...@michelf.ca wrote: On 2013-06-10 14:11:31 +, David Nadlinger c...@klickverbot.at said: On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote: On 10 June 2013 23:46, David Nadlinger c...@klickverbot.at Another less intrusive option would be to just add extern(CppThisCall) and extern(DThisCall) or something along the lines, which would be specified to pass the first parameter as if it was a this pointer. That would also do the business. Do you think that's less intrusive? Less intrusive in the way that it is a minimal addition to the language itself (we already have several calling conventions), whereas your suggestion would require adding a special case to the grammar. That's not to say I don't like your proposal, though. I just wanted to put the option on the table to be sure we are getting somewhere with this, even if some people might be opposed to the grammar change. This issue has been bugging me for quite some time as well. It's inelegant, but it could work. I just find it sad that we have to use a different calling convention for member functions. I mean, it'd be much more elegant be if a member function could simply be called from a void function(Object) by supplying this as the first argument? Wouldn't it be better to adapt the ABI to fit the language rather than adapt the language to fit the ABI? The ABI is the better part of half a century old...
Re: Member function pointers
On 2013-06-10 14:11:31 +, David Nadlinger c...@klickverbot.at said: On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote: On 10 June 2013 23:46, David Nadlinger c...@klickverbot.at Another less intrusive option would be to just add extern(CppThisCall) and extern(DThisCall) or something along the lines, which would be specified to pass the first parameter as if it was a this pointer. That would also do the business. Do you think that's less intrusive? Less intrusive in the way that it is a minimal addition to the language itself (we already have several calling conventions), whereas your suggestion would require adding a special case to the grammar. That's not to say I don't like your proposal, though. I just wanted to put the option on the table to be sure we are getting somewhere with this, even if some people might be opposed to the grammar change. This issue has been bugging me for quite some time as well. It's inelegant, but it could work. I just find it sad that we have to use a different calling convention for member functions. I mean, it'd be much more elegant be if a member function could simply be called from a void function(Object) by supplying this as the first argument? Wouldn't it be better to adapt the ABI to fit the language rather than adapt the language to fit the ABI? -- Michel Fortin michel.for...@michelf.ca http://michelf.ca/
Re: Member function pointers
On 2013-06-10 15:47, Manu wrote: I'm really not asking for delegates (although they could become more typesafe given my suggestion), just a member function pointer. And not C++ style as you say, my suggestion is much simpler than that, and would fit nicely in D. I give up, I don't understand what you want. -- /Jacob Carlborg
Re: Member function pointers
On 11 June 2013 00:43, Jacob Carlborg d...@me.com wrote: On 2013-06-10 15:47, Manu wrote: I'm really not asking for delegates (although they could become more typesafe given my suggestion), just a member function pointer. And not C++ style as you say, my suggestion is much simpler than that, and would fit nicely in D. I give up, I don't understand what you want. ...a member function pointer syntax. It's not that complex. My suggestion is: void function(T this) funcptr; This is a function pointer (not a delegate), but using keyword 'this' gives the critical detail to the compiler that it's a member function pointer, and to use the appropriate calling convention when making calls through this pointer. UFCS makes it awesome.
Re: Member function pointers
On Monday, 10 June 2013 at 14:43:50 UTC, Jacob Carlborg wrote: On 2013-06-10 15:47, Manu wrote: I'm really not asking for delegates (although they could become more typesafe given my suggestion), just a member function pointer. And not C++ style as you say, my suggestion is much simpler than that, and would fit nicely in D. I give up, I don't understand what you want. Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- David
Re: Member function pointers
On 2013-06-10 17:36, Manu wrote: My suggestion is: void function(T this) funcptr; This is a function pointer (not a delegate), but using keyword 'this' gives the critical detail to the compiler that it's a member function pointer, and to use the appropriate calling convention when making calls through this pointer. UFCS makes it awesome. What I don't understand is what this give you that a delegate doesn't. You need the this pointer to call the function pointer anyway. With a delegate it's bundled. -- /Jacob Carlborg
Re: Member function pointers
On 2013-06-10 17:40, David Nadlinger wrote: Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- Why is this better than a delegate? -- /Jacob Carlborg
Re: Member function pointers
On 11 June 2013 02:26, Jacob Carlborg d...@me.com wrote: On 2013-06-10 17:40, David Nadlinger wrote: Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- Why is this better than a delegate? It's not 'better', it's different.
Re: Member function pointers
On 11 June 2013 02:28, Jacob Carlborg d...@me.com wrote: On 2013-06-10 17:36, Manu wrote: My suggestion is: void function(T this) funcptr; This is a function pointer (not a delegate), but using keyword 'this' gives the critical detail to the compiler that it's a member function pointer, and to use the appropriate calling convention when making calls through this pointer. UFCS makes it awesome. What I don't understand is what this give you that a delegate doesn't. You need the this pointer to call the function pointer anyway. With a delegate it's bundled. It's just a pointer, 'this' is associated at the call site. And it's strongly typed. If you don't want a bundle, why be forced to use a bundled type? Consider this, why would you ever want an int* when you can have an int[]? We could remove the syntax for int*, and make it only accessible via int[].ptr... and make: is(typeof(int[].ptr) == size_t)? :)
Re: Member function pointers
On 2013-06-10 18:34, Manu wrote: On 11 June 2013 02:26, Jacob Carlborg d...@me.com mailto:d...@me.com wrote: On 2013-06-10 17:40, David Nadlinger wrote: Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- Why is this better than a delegate? It's not 'better', it's different. class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; void delegate () dg; dg.funcptr = memberFun; dg.ptr = cast(void*) a; dg(); The details can be hidden in a function call. Sure, a delegate could be type safe but still don't see the point. -- /Jacob Carlborg
Re: Member function pointers
Am 10.06.2013 18:28, schrieb Jacob Carlborg: On 2013-06-10 17:36, Manu wrote: My suggestion is: void function(T this) funcptr; This is a function pointer (not a delegate), but using keyword 'this' gives the critical detail to the compiler that it's a member function pointer, and to use the appropriate calling convention when making calls through this pointer. UFCS makes it awesome. What I don't understand is what this give you that a delegate doesn't. You need the this pointer to call the function pointer anyway. With a delegate it's bundled. maybe he just don't need one to handle the this ptr because he wants to call several/hundrets of member-functions?
Re: Member function pointers
On 2013-06-10 18:38, dennis luehring wrote: maybe he just don't need one to handle the this ptr because he wants to call several/hundrets of member-functions? How does he call a pointer to a member function without the this pointer? -- /Jacob Carlborg
Re: Member function pointers
On 11 June 2013 02:43, Jacob Carlborg d...@me.com wrote: On 2013-06-10 18:34, Manu wrote: On 11 June 2013 02:26, Jacob Carlborg d...@me.com mailto:d...@me.com wrote: On 2013-06-10 17:40, David Nadlinger wrote: Let me try to summarize it in code: --- class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; memberFun(a); --- Why is this better than a delegate? It's not 'better', it's different. class A { void foo(); } auto memberFun = (A.foo).funcptr; auto a = new A; void delegate () dg; dg.funcptr = memberFun; dg.ptr = cast(void*) a; dg(); The details can be hidden in a function call. Sure, a delegate could be type safe but still don't see the point. You can see how much work that is right? And it's still not typesafe. It's totally a hack.
Re: Member function pointers
On Mon, 10 Jun 2013 12:45:12 -0400, Jacob Carlborg d...@me.com wrote: On 2013-06-10 18:38, dennis luehring wrote: maybe he just don't need one to handle the this ptr because he wants to call several/hundrets of member-functions? How does he call a pointer to a member function without the this pointer? Like this: void callRandomMember(C[] objs, memberPointerToCMethod p) { objs[random(0, objs.length)].p(); } Essentially, you bind at call time to form a delegate. But the member function pointer's 'this' must be strongly typed. -Steve
Re: Member function pointers
On Mon, 10 Jun 2013 14:53:33 +0200, Jacob Carlborg d...@me.com wrote: On 2013-06-10 14:36, Manu wrote: 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. This is utter horseshit. Not that it's part of the complete type, nor even that it becomes complete with the context pointer (though that is highly dubious at best), but the type of funcptr. It's a disgrace, simple as that. It should either be typeless, or it should take a void* as its first argument. void* means 'magic ahead', so it would be kinda ok. -- Simen
Re: Member function pointers
On Monday, 10 June 2013 at 20:31:32 UTC, Simen Kjaeraas wrote: or it should take a void* as its first argument. void* means 'magic ahead', so it would be kinda ok. This would encourage people to try something like dg.funcptr(dg.ptr, ...), which is not correct ABI-wise. David
Re: Member function pointers
Manu, is this that you want? class C { int foo() { printf(invoke C.foo()\n); return 1; } int bar() { printf(invoke C.bar()\n); return 2; } int bar(string s) { printf(invoke C.bar(string)\n); return s.length; } } class D : C { override int foo() { printf(invoke D.func\n); return 4; } } void main() { D d = new D(); MemFunPtr!C.foo!() fpFoo = d; MemFunPtr!C.bar!() fpBar = d; MemFunPtr!C.bar!(string) fpBar2 = d; assert(fpFoo() == 4); assert(fpBar() == 2); assert(fpBar2(hello) == 5); static assert(fpFoo.sizeof == (void*).sizeof); } // - // Implementation // - import std.traits, std.typetuple; template MemFunPtr(C) if (is(C == class)) { mixin GenName!C; } mixin template GenName(C, size_t i = 0) { alias names = allMembers!C; static if (i = names.length) { /* do nothing */ } else { enum name = names[i]; alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, name)); static if (vfuncs.length 0) { struct _Impl(Params...) { private: C obj; alias VtblEntry = GetVtblEntry!(C, name, Params); private: this(C obj) { this.obj = obj; } auto ref opCall(Params args) { alias R = ReturnType!(VtblEntry.func); R delegate(Params) dg; dg.ptr = *cast(void**)obj; dg.funcptr = cast(R function(Params))obj.__vptr[VtblEntry.vindex]; return dg(args); } } mixin(alias _Impl ~name~;); } mixin .GenName!(C, i + 1); } } template GetVtblEntry(C, string name, Params...) { alias names = allMembers!C; template Impl(size_t ofs, size_t i) { alias vfuncs = TypeTuple!(__traits(getVirtualFunctions, C, names[i])); static if (names[i] != name) { alias Impl = Impl!(ofs + vfuncs.length, i + 1); } else { static assert(vfuncs.length 0); template Impl2(size_t j) { static if (is(ParameterTypeTuple!(vfuncs[j]) == Params)) { enum vindex = ofs + j; alias func = vfuncs[j]; } else alias Impl2 = Impl2!(j + 1); } alias Impl = Impl2!(0); } } alias GetVtblEntry = Impl!(1/*vtbl[0] == TypeInfo*/, 0); } template baseMembers(BC...) { static if (BC.length 1) { alias baseMembers = TypeTuple!( allMembers!(BC[0]), baseMembers!(BC[1 .. $]) ); } else static if (BC.length == 1) { alias baseMembers = allMembers!(BC[0]); } else alias baseMembers = TypeTuple!(); } template derivedMembers(C) { alias derivedMembers = TypeTuple!( __traits(derivedMembers, C) ); } template allMembers(C) { alias allMembers = TypeTuple!( baseMembers!(BaseClassesTuple!C), __traits(derivedMembers, C) ); } Kenji Hara 2013/6/8 Manu turkey...@gmail.com 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. Now taken this as a declaration syntax, I think calls would be made via UFCS. T x; void function(T this) mp; mp(x); // I guess this is fine x.mp(); // but UFCS really makes this concept nice! So the final detail, is how to capture one of these member function pointers from within D... I initially thought about a syntax, but this is so niche, I don't think it warrants a syntax. So my current best idea is to introduce 2 properties to delegates, so that the function pointer (of this type) can be accessed via the delegate syntax. delegate d = x.f; void function(T this) mp = d.funcPtr; An interesting side effect, is that
Re: Member function pointers
On Friday, 7 June 2013 at 23:22:03 UTC, Manu wrote: Currently, to get the instance or function pointers from a delegate, you need to do something like: delegates have two members, ptr and funcptr: http://dlang.org/function.html As a fun fact, if you modify druntime's allocator to be malloc(), you can use free(delegate.ptr) to manually manage closures, though this takes a lot of care to know if it actually should be freed or not. Anyway, the ptr member there is always void*, however, so at least one cast is required to actually use it. Perhaps the language could be extended to make this strongly typed, but then you'd have to change the whole visible type as assigning say, a closure to a delegate variable would need to be a different type than a class member; I guess this is what you're talking about though. idk, I've kinda wanted pointer to members before but I also think D's delegates being so versatile and interchangeable is totally boss. I don't know a syntax to describe the type of a closure, so when a delegate is typed with a closure instead of a struct/class, what is 'C' in the struct template above? That's a tricky one, perhaps it could be a tuple of the captured variables' type.
Re: Member function pointers
On 2013-06-07 23:21:53 +, Manu turkey...@gmail.com said: Thoughts? Reminds me of something similar I implemented a while ago: http://michelf.ca/projects/d-objc/syntax/#selector-literals Not only I think member function pointers are doable, but I think they're solely missing. There have been situations where I'd have used them but instead had to hack my way using a delegate. That was to build a bridge for Objective-C (before I decided to hack the compiler). I'd guess you're doing something of the sort too? -- Michel Fortin michel.for...@michelf.ca http://michelf.ca/
Re: Member function pointers
On 8 June 2013 09:42, Adam D. Ruppe destructiona...@gmail.com wrote: On Friday, 7 June 2013 at 23:22:03 UTC, Manu wrote: Currently, to get the instance or function pointers from a delegate, you need to do something like: delegates have two members, ptr and funcptr: http://dlang.org/function.html As a fun fact, if you modify druntime's allocator to be malloc(), you can use free(delegate.ptr) to manually manage closures, though this takes a lot of care to know if it actually should be freed or not. Anyway, the ptr member there is always void*, however, so at least one cast is required to actually use it. Perhaps the language could be extended to make this strongly typed, but then you'd have to change the whole visible type as assigning say, a closure to a delegate variable would need to be a different type than a class member; I guess this is what you're talking about though. Indeed, I apologise for my ignorance! The properties are already there... but they're not properly typed. idk, I've kinda wanted pointer to members before but I also think D's delegates being so versatile and interchangeable is totally boss. I agree, a delegate is almost always what I want. But a delegate is really just a compound concept, and without a way to express it's fundamental parts, which in certain circumstances (like in my case) are useful on their own, then it feels like a bit of magic. I don't know a syntax to describe the type of a closure, so when a delegate is typed with a closure instead of a struct/class, what is 'C' in the struct template above? That's a tricky one, perhaps it could be a tuple of the captured variables' type. Yeah, that was my initial feeling too... and I think it could be quite workable in that way.
Re: Member function pointers
On 8 June 2013 09:48, Michel Fortin michel.for...@michelf.ca wrote: On 2013-06-07 23:21:53 +, Manu turkey...@gmail.com said: Thoughts? Reminds me of something similar I implemented a while ago: http://michelf.ca/projects/d-**objc/syntax/#selector-literalshttp://michelf.ca/projects/d-objc/syntax/#selector-literals Not only I think member function pointers are doable, but I think they're solely missing. There have been situations where I'd have used them but instead had to hack my way using a delegate. That was to build a bridge for Objective-C (before I decided to hack the compiler). I'd guess you're doing something of the sort too? Precisely. The concept is already embedded inside of delegate, but delegate is framed like a piece of magic, rather than a well defined compound of more primitive pieces. Those primitive pieces would be useful in certain cases (like mine, and yours). I think the only missing detail is a way to express a 'thiscall' function pointer, which I believe my suggestion satisfies quite nicely.
Re: Member function pointers
On Friday, 7 June 2013 at 23:54:55 UTC, Manu wrote: The properties are already there... but they're not properly typed. I just don't think they can be unless we change the visible type which isn't always what we want but, check this out: // this new type keeps track of the exact type of the pointer // and manages the delegate so we can cast with some sanity... struct PointerToMemberFunction(Class, Ret, T...) if(is(Class : Object)) { private Ret delegate(T) dg; @property Class object() { return cast(Class) dg.ptr; } @property void object(Class rhs) { dg.ptr = cast(void*) rhs; } Ret opCall(T t) { assert(dg.ptr !is null, null this); static if(is(Ret == void)) dg(t); else return dg(t); } } // this helps us construct the above template ptrToMember(alias blargh) { // I'm writing out the function template longhand // because I want to use blargh as a type and // dmd won't let me do it without an intermediate // dmd complains type expected, not __traits so we use // this to work around it template workaround(T) { alias workaround = T; } alias ObjectType = workaround!(__traits(parent, blargh)); auto ptrToMember(ObjectType a = null) { import std.traits; PointerToMemberFunction!( ObjectType, ReturnType!blargh, ParameterTypeTuple!blargh ) mem; mem.dg.funcptr = blargh; mem.dg.ptr = cast(void*) a; return mem; } } actually i just realized maybe this should not be a function at all, so it is easy to use as a class member, without having to write an extra typeof(). That's probably more valuable than the initialiser which as you'll see below is optional anyway. Anyway, then you can use it like this: class A { void foo() {writeln(foo from , name);} int bar(string s) {writeln(bar ,s, from , name); return 10; } this(string n) { name = n; } string name; } class B : A { this(string n) { super(n); } override void foo() { writeln(derived foo from , name); } } void main() { A a = new A(a); B c = new B(c); Object ob = a; auto ptr = ptrToMember!(B.foo)(c); // initialize the object here ptr(); ptr.object = a; ptr(); auto ptr2 = ptrToMember!(A.bar); // initialize to null.. ptr2.object = ptr.object; // can assign later ptr2(hey); } And if you play around with the types there, you'll see the compile will fail if you do something uncool. Though the error messages sometimes suck, what the hell: test2.d(58): Error: not a property ptr.object... actually it is, but I was passing it an A when it required a B. That's a type mismatch, not a missing property. But whatever, at least it *did* fail to compile, so we have our type safety. And if I threw in an alias this on a getter property, we could assign these beasties to regular delegates too. Not half bad. But regular delegate assigning to this is prohibited because we can't be sure their context pointer is the right kind of class. This would be true if the compiler automatically did the ptrToMember!() too, so let's say we change a.foo to return one of these strongly typed things instead of a void* delegate like it does now. auto ptr = a.foo; // is ptr a void delegate() or a pointer to specifically a void() member of class A? That matters because if the former (current behavior), this compiles: ptr = { writeln(hello!); }; but if the latter, that will not, it will complain that the this pointers are of mismatching type (or not a property lol). Of course, with alias this style behavior, you could explicitly write out void delegate() ptr = a.foo; // ok, use looser type ptr = {...}; // perfectly fine So I guess we wouldn't be losing much, but since we both agree a delegate is almost always what we want, maybe the library solution of ptrToMember is better to keep auto in a Just Works state. I'm presuming you're already doing something similar for your C++ interop, if not, I'm pretty sure this same idea would work there too, at least to a 'good enough' state, even if not technically portable. Yeah, that was my initial feeling too... and I think it could be quite workable in that way. Aye, and this would require the compiler's help. Can't hit 'good enough' on that with templates.
Re: Member function pointers
On 8 June 2013 10:24, Adam D. Ruppe destructiona...@gmail.com wrote: On Friday, 7 June 2013 at 23:54:55 UTC, Manu wrote: The properties are already there... but they're not properly typed. I just don't think they can be unless we change the visible type which isn't always what we want but, check this out: // this new type keeps track of the exact type of the pointer // and manages the delegate so we can cast with some sanity... struct PointerToMemberFunction(Class, Ret, T...) if(is(Class : Object)) { private Ret delegate(T) dg; @property Class object() { return cast(Class) dg.ptr; } @property void object(Class rhs) { dg.ptr = cast(void*) rhs; } Ret opCall(T t) { assert(dg.ptr !is null, null this); static if(is(Ret == void)) dg(t); else return dg(t); } } // this helps us construct the above template ptrToMember(alias blargh) { // I'm writing out the function template longhand // because I want to use blargh as a type and // dmd won't let me do it without an intermediate // dmd complains type expected, not __traits so we use // this to work around it template workaround(T) { alias workaround = T; } alias ObjectType = workaround!(__traits(parent, blargh)); auto ptrToMember(ObjectType a = null) { import std.traits; PointerToMemberFunction!( ObjectType, ReturnType!blargh, ParameterTypeTuple!blargh ) mem; mem.dg.funcptr = blargh; mem.dg.ptr = cast(void*) a; return mem; } } actually i just realized maybe this should not be a function at all, so it is easy to use as a class member, without having to write an extra typeof(). That's probably more valuable than the initialiser which as you'll see below is optional anyway. Anyway, then you can use it like this: class A { void foo() {writeln(foo from , name);} int bar(string s) {writeln(bar ,s, from , name); return 10; } this(string n) { name = n; } string name; } class B : A { this(string n) { super(n); } override void foo() { writeln(derived foo from , name); } } void main() { A a = new A(a); B c = new B(c); Object ob = a; auto ptr = ptrToMember!(B.foo)(c); // initialize the object here ptr(); ptr.object = a; ptr(); auto ptr2 = ptrToMember!(A.bar); // initialize to null.. ptr2.object = ptr.object; // can assign later ptr2(hey); } And if you play around with the types there, you'll see the compile will fail if you do something uncool. Though the error messages sometimes suck, what the hell: test2.d(58): Error: not a property ptr.object... actually it is, but I was passing it an A when it required a B. That's a type mismatch, not a missing property. But whatever, at least it *did* fail to compile, so we have our type safety. And if I threw in an alias this on a getter property, we could assign these beasties to regular delegates too. Not half bad. But regular delegate assigning to this is prohibited because we can't be sure their context pointer is the right kind of class. This would be true if the compiler automatically did the ptrToMember!() too, so let's say we change a.foo to return one of these strongly typed things instead of a void* delegate like it does now. auto ptr = a.foo; // is ptr a void delegate() or a pointer to specifically a void() member of class A? That matters because if the former (current behavior), this compiles: ptr = { writeln(hello!); }; but if the latter, that will not, it will complain that the this pointers are of mismatching type (or not a property lol). Of course, with alias this style behavior, you could explicitly write out void delegate() ptr = a.foo; // ok, use looser type ptr = {...}; // perfectly fine So I guess we wouldn't be losing much, but since we both agree a delegate is almost always what we want, maybe the library solution of ptrToMember is better to keep auto in a Just Works state. I'm presuming you're already doing something similar for your C++ interop, if not, I'm pretty sure this same idea would work there too, at least to a 'good enough' state, even if not technically portable. I initially started with something like this. But look how much code it is! I actually deleted it all and went for my non-portable hack. My implementation was different. You've basically wrapped up a delegate, and made something that emulates a delegate (I'm not sure why?). I don't want a delegate, I want a function pointer. So my solution was similar, but wrapped up a function pointer and aliased a delegate to
Re: Member function pointers
On Saturday, 8 June 2013 at 01:11:46 UTC, Manu wrote: I initially started with something like this. But look how much code it is! Yeah... You've basically wrapped up a delegate, and made something that emulates a delegate (I'm not sure why?). I just wanted to add type safety to a delegate; to get rid of the visible cast(void*) and vice versa, to see what it would look like.
Re: Member function pointers
On 2013-06-07 23:57:40 +, Manu turkey...@gmail.com said: Precisely. The concept is already embedded inside of delegate, but delegate is framed like a piece of magic, rather than a well defined compound of more primitive pieces. Delegates are not parametrized on the type of this, which makes them easier to move around. I would not change delegates. But function pointers with a this parameter would be useful. You can achieve this using a template struct containing a pointer and a call method: the call method would generate a local delegate variable from the pointer and and call it. What you can't do without compiler support is get such a pointer in a type-safe manner. -- Michel Fortin michel.for...@michelf.ca http://michelf.ca/
Re: Member function pointers
On 8 June 2013 12:29, Michel Fortin michel.for...@michelf.ca wrote: On 2013-06-07 23:57:40 +, Manu turkey...@gmail.com said: Precisely. The concept is already embedded inside of delegate, but delegate is framed like a piece of magic, rather than a well defined compound of more primitive pieces. Delegates are not parametrized on the type of this, which makes them easier to move around. I would not change delegates. Actually, that's very true. Good point, and I think this is almost the key distinction. But function pointers with a this parameter would be useful. You can achieve this using a template struct containing a pointer and a call method: the call method would generate a local delegate variable from the pointer and and call it. What you can't do without compiler support is get such a pointer in a type-safe manner. Yup, this is what I originally did. It's big and ugly, I didn't like it, and deleted it. I think the syntax I suggest is simple and obvious, and naturally, typesafe.