www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Member function pointers

reply Manu <turkeyman gmail.com> writes:
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 'delegate' could actually be understood
as a strongly-typed small struct, whereas currently, it's just a magic
thing:

Given: RT delegate(A x, B y) d = &c.m;

It would look like:
struct delegate(C)
{
  C thisPointer;
  RT function(C this, A x, B, y) funcPointer;
}

Currently, to get the instance or function pointers from a delegate, you
need to do something like:
delegate d;
void** pd = cast(void**)&d;
T instancePointer = cast(T)pd[0];
void function(T this) functionPointer = cast(RT function(T this))pd[1];

Casting through a void array like that is pretty horrible.
Adding 2 properties to delegate to get either of those things can makes
sense once it is possible to express the type of the function pointer,
which would now be possible with the syntax above.

So, I quite like the transparency introduced when a delegate can be
explicitly described in the language. But there is one loose detail...

void f()
{
  void g() {}
  void delegate() d = &g; // delegate 'this' is a closure
}

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?


Thoughts?
Is there reason to outright ban this sort of expression?
I think this actually clarifies some details of the language, and reduces a
currently 'magic' thing into a well-defined, strongly-typed concept.

- Manu
Jun 07 2013
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Jun 07 2013
parent reply Manu <turkeyman gmail.com> writes:
On 8 June 2013 09:42, Adam D. Ruppe <destructionator 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.
Jun 07 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Jun 07 2013
parent reply Manu <turkeyman gmail.com> writes:
On 8 June 2013 10:24, Adam D. Ruppe <destructionator 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 the correct type, then created a local delegate populating with 'this' and the function at the call-site... But it's all crap! It's really just abusing a delegate to get at the concept it embed's which doesn't have a proper expression.
Jun 07 2013
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Jun 07 2013
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-06-07 23:21:53 +0000, Manu <turkeyman 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.fortin michelf.ca http://michelf.ca/
Jun 07 2013
parent reply Manu <turkeyman gmail.com> writes:
On 8 June 2013 09:48, Michel Fortin <michel.fortin michelf.ca> wrote:

 On 2013-06-07 23:21:53 +0000, Manu <turkeyman gmail.com> said:

  Thoughts?

 Reminds me of something similar I implemented a while ago:
 http://michelf.ca/projects/d-**objc/syntax/#selector-literals<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?
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.
Jun 07 2013
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-06-07 23:57:40 +0000, Manu <turkeyman 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.fortin michelf.ca http://michelf.ca/
Jun 07 2013
parent Manu <turkeyman gmail.com> writes:
On 8 June 2013 12:29, Michel Fortin <michel.fortin michelf.ca> wrote:

 On 2013-06-07 23:57:40 +0000, Manu <turkeyman 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.
Jun 07 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 09 2013
parent reply Manu <turkeyman gmail.com> writes:
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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
next sibling parent reply Manu <turkeyman gmail.com> writes:
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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
parent reply Manu <turkeyman gmail.com> writes:
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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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.
Jun 10 2013
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On 10 June 2013 22:53, Jacob Carlborg <doob 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.
Jun 10 2013
parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Jun 10 2013
parent Manu <turkeyman gmail.com> writes:
On 10 June 2013 23:49, David Nadlinger <code 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.
Jun 10 2013
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 10 Jun 2013 14:53:33 +0200, Jacob Carlborg <doob 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
Jun 10 2013
parent "David Nadlinger" <code klickverbot.at> writes:
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
Jun 10 2013
prev sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
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/
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
parent reply Manu <turkeyman gmail.com> writes:
On 10 June 2013 22:56, Jacob Carlborg <doob 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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 11 June 2013 00:43, Jacob Carlborg <doob 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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
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?
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 10 Jun 2013 12:45:12 -0400, Jacob Carlborg <doob 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
Jun 10 2013
prev sibling parent Manu <turkeyman gmail.com> writes:
On 11 June 2013 02:28, Jacob Carlborg <doob 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)? :)
Jun 10 2013
prev sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
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
Jun 10 2013
parent reply Manu <turkeyman gmail.com> writes:
On 11 June 2013 02:26, Jacob Carlborg <doob 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.
Jun 10 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-06-10 18:34, Manu wrote:
 On 11 June 2013 02:26, Jacob Carlborg <doob me.com <mailto:doob 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
Jun 10 2013
next sibling parent Manu <turkeyman gmail.com> writes:
On 11 June 2013 02:43, Jacob Carlborg <doob me.com> wrote:

 On 2013-06-10 18:34, Manu wrote:

 On 11 June 2013 02:26, Jacob Carlborg <doob me.com <mailto:doob 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.
Jun 10 2013
prev sibling next sibling parent d coder via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Mon, Jun 10, 2013 at 10:13 PM, Jacob Carlborg <doob me.com> wrote:

 On 2013-06-10 18:34, Manu wrote:

 On 11 June 2013 02:26, Jacob Carlborg <doob me.com <mailto:doob 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
May 27 2014
prev sibling parent reply d coder via Digitalmars-d <digitalmars-d puremagic.com> writes:
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
May 27 2014
parent reply "Prudence" <Pursuit Happyness.All> writes:
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 = &xX.foo; //x.dg(3); x.ptr = &xX; x.funcptr(xX, 5); //x.funcptr(5); getch(); } Unfortunately this fails when entering the function. I've tried various things(passing &xX, 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?
Sep 09 2015
parent "bitwise" <bitwise.pvt gmail.com> writes:
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 = &xX.foo; //x.dg(3); x.ptr = &xX; x.funcptr(xX, 5); //x.funcptr(5); getch(); } Unfortunately this fails when entering the function. I've tried various things(passing &xX, 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 = &s.fun; fn1(); C c = new C(); void delegate() fn2 = &c.fun; fn2(); void delegate() fn3; fn3.ptr = cast(void*)&s; fn3.funcptr = &S.fun; fn3(); void delegate() fn4; fn4.ptr = cast(void*)c; fn4.funcptr = &C.fun; fn4(); }
Sep 09 2015
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
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
Jun 10 2013
prev sibling next sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Jun 10 2013
parent reply Manu <turkeyman gmail.com> writes:
On 10 June 2013 23:46, David Nadlinger <code 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.
Jun 10 2013
parent reply "David Nadlinger" <code klickverbot.at> writes:
On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote:
 On 10 June 2013 23:46, David Nadlinger <code 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
Jun 10 2013
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-06-10 14:11:31 +0000, "David Nadlinger" <code klickverbot.at> said:

 On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote:
 On 10 June 2013 23:46, David Nadlinger <code 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.fortin michelf.ca http://michelf.ca/
Jun 10 2013
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 11 June 2013 00:28, Michel Fortin <michel.fortin michelf.ca> wrote:

 On 2013-06-10 14:11:31 +0000, "David Nadlinger" <code klickverbot.at>
 said:

  On Monday, 10 June 2013 at 14:04:29 UTC, Manu wrote:
 On 10 June 2013 23:46, David Nadlinger <code 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...
Jun 10 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/10/2013 7:33 AM, Manu wrote:
 [...]
Sorry to say, your n.g. poster is back to its old tricks :-)
Sep 09 2015
next sibling parent reply "Freddy" <Hexagonalstar64 gmail.com> writes:
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.
Sep 09 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
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.
Sep 09 2015
prev sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 10 September 2015 at 04:55, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 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? ;)
Sep 09 2015
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/9/2015 6:52 PM, Manu via Digitalmars-d wrote:
 We've resolved this issue since 6/10/2013 no? ;)
:-)
Sep 09 2015
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 10 September 2015 at 01:52:17 UTC, digitalmars.D 
wrote:
 On 10 September 2015 at 04:55, Walter Bright via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:
 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?
Sep 10 2015
parent reply "Vladimir Panteleev" <thecybershadow.lists gmail.com> writes:
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-d 
 <digitalmars-d puremagic.com> wrote:
 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).
Sep 10 2015
next sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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".
Sep 10 2015
parent reply "Vladimir Panteleev" <thecybershadow.lists gmail.com> writes:
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.
Sep 10 2015
parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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
Sep 10 2015
parent reply "Vladimir Panteleev" <thecybershadow.lists gmail.com> writes:
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.
Sep 10 2015
parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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.
Sep 10 2015
prev sibling parent reply "data man" <datamanrb gmail.com> writes:
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.
Sep 10 2015
parent "Vladimir Panteleev" <thecybershadow.lists gmail.com> writes:
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.
Sep 11 2015
prev sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Michel Fortin" <michel.fortin 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.
Jun 11 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
Sep 09 2015
parent reply "Freddy" <Hexagonalstar64 gmail.com> writes:
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); }
Sep 09 2015
parent "Freddy" <Hexagonalstar64 gmail.com> writes:
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)});
Sep 09 2015