digitalmars.D - Address of UFCS call implicity converts to Delegate
- Jonathan Marler (27/27) Apr 23 2017 This feels like a natural extension to existing semantics. It
- Basile B. (28/57) Apr 23 2017 What would be the usage of this ?
- Jonathan Marler (3/4) Apr 23 2017 For the same reason that UFCS exists. You can't add "member
- Basile B. (4/8) Apr 23 2017 Good point. I have to say that this feature then makes me think
- Jonathan Marler (33/42) Apr 24 2017 I've added a DIP for this (https://github.com/dlang/DIPs/pull/61).
- Jonathan Marler (4/19) Apr 24 2017 Scratch the "Extension Methods" idea. I've found a more
- Meta (5/38) Apr 24 2017 One small tweak is that `this` should act as a storage class
- Jonathan Marler (10/57) Apr 24 2017 Yes I'm familiar with C# extension methods and that was my
This feels like a natural extension to existing semantics. It doesn't require new syntax and serves as a solution to some issues when working with delegates. Say some API wants a delegate like this: void delegate(string arg) With this feature, you could take a function like this: void myCoolFunction(MyClassObject obj, string arg) { // ... } and the following would have the same delegate type: &myClassObject.myCoolFunction // type is void delegate(string arg) This of course wouldn't work for all functions. The first parameter of the function would need to have the same calling convention as the "this" parameter for a "delegate". void cantBecomeDelegate(SomeBigStructType s) { } &myStruct.cantBecomeDelegate // Error error: cannot convert UFCS call to delegate because the first parameter of function 'cantBecomeDelegate' is too large. Consider adding "ref" to the first parameter or making it a pointer. To fix this you could do something like this: void canBecomeDelegate(ref SomeBigStructType s) { } &myStruct.canBecomeDelegate // OK!
Apr 23 2017
On Sunday, 23 April 2017 at 16:32:06 UTC, Jonathan Marler wrote:This feels like a natural extension to existing semantics. It doesn't require new syntax and serves as a solution to some issues when working with delegates. Say some API wants a delegate like this: void delegate(string arg) With this feature, you could take a function like this: void myCoolFunction(MyClassObject obj, string arg) { // ... } and the following would have the same delegate type: &myClassObject.myCoolFunction // type is void delegate(string arg) This of course wouldn't work for all functions. The first parameter of the function would need to have the same calling convention as the "this" parameter for a "delegate". void cantBecomeDelegate(SomeBigStructType s) { } &myStruct.cantBecomeDelegate // Error error: cannot convert UFCS call to delegate because the first parameter of function 'cantBecomeDelegate' is too large. Consider adding "ref" to the first parameter or making it a pointer. To fix this you could do something like this: void canBecomeDelegate(ref SomeBigStructType s) { } &myStruct.canBecomeDelegate // OK!What would be the usage of this ? Actually i think i see the ABI trick you want to use. And it works: ================== import std.stdio; alias ProtoD = void delegate(size_t); alias ProtoF = void function(size_t); class Foo{size_t a;} extern(C) void pseudoMemberFunc(Foo foo, size_t a) { foo.a = a;} void main() { Foo foo = new Foo; // under the hood it's what would make "&foo.pseudoMemberFunc;" ProtoD dg; dg.funcptr = cast(ProtoF) &pseudoMemberFunc; dg.ptr = cast(void*) foo; // close the hood carefully dg(42); writeln(foo.a); } It works in extern(C) only because of parameter order. ================== But: 1/ It's dangerous because then nothing guarantees anymore that .funcptr is a n actual member function. 2/ Why not just a member function ?
Apr 23 2017
On Sunday, 23 April 2017 at 17:00:59 UTC, Basile B. wrote:2/ Why not just a member function ?For the same reason that UFCS exists. You can't add "member functions" to external library types.
Apr 23 2017
On Sunday, 23 April 2017 at 17:07:51 UTC, Jonathan Marler wrote:On Sunday, 23 April 2017 at 17:00:59 UTC, Basile B. wrote:Good point. I have to say that this feature then makes me think to what's called "class helpers" in the Delphi/Object Pascal world. That's exactly for what they're used.2/ Why not just a member function ?For the same reason that UFCS exists. You can't add "member functions" to external library types.
Apr 23 2017
On Sunday, 23 April 2017 at 17:13:31 UTC, Basile B. wrote:On Sunday, 23 April 2017 at 17:07:51 UTC, Jonathan Marler wrote:I've added a DIP for this (https://github.com/dlang/DIPs/pull/61). At first I first thought that all we needed was to add semantics to take the address of a UFCS-style call, but after messing around with your example I realized that delegates are not ABI-compatible with functions that take the delegate ptr as the first parameter. You mentioned that the problem was with the parameter order and that this should work with extern(C) functions and I think you're right. The new DIP proposes the addition of "Extension Methods" which are functions that are ABI-compatible with delegates. You define an extension method by naming the first parameter "this": struct Foo { void bar(int x) { } } void baz(ref Foo this, int x) { } Because the first parameter of baz is named this, it is an "extension method" of Foo which means it is ABI-compatible with the method bar. void delegate(int x) dg; Foo foo; dg = &foo.bar; // a normal method delegate dg(42); // calls foo.bar(42) dg = &foo.baz; // an extension method delegate dg(42); // calls baz(foo, 42); dg = &baz; // a "null delegate", unsafe code, funcptr points to the baz function, but ptr is null dg(42); // calls baz(null, 42);On Sunday, 23 April 2017 at 17:00:59 UTC, Basile B. wrote:Good point. I have to say that this feature then makes me think to what's called "class helpers" in the Delphi/Object Pascal world. That's exactly for what they're used.2/ Why not just a member function ?For the same reason that UFCS exists. You can't add "member functions" to external library types.
Apr 24 2017
On Monday, 24 April 2017 at 15:47:14 UTC, Jonathan Marler wrote:On Sunday, 23 April 2017 at 17:13:31 UTC, Basile B. wrote:Scratch the "Extension Methods" idea. I've found a more generalized way to do the same thing. I'm calling it "Delegateable Functions" (https://github.com/dlang/DIPs/pull/61).[...]I've added a DIP for this (https://github.com/dlang/DIPs/pull/61). At first I first thought that all we needed was to add semantics to take the address of a UFCS-style call, but after messing around with your example I realized that delegates are not ABI-compatible with functions that take the delegate ptr as the first parameter. You mentioned that the problem was with the parameter order and that this should work with extern(C) functions and I think you're right. The new DIP proposes the addition of "Extension Methods" which are functions that are ABI-compatible with delegates. You define an extension method by naming the first parameter "this": [...]
Apr 24 2017
On Monday, 24 April 2017 at 15:47:14 UTC, Jonathan Marler wrote:I've added a DIP for this (https://github.com/dlang/DIPs/pull/61). At first I first thought that all we needed was to add semantics to take the address of a UFCS-style call, but after messing around with your example I realized that delegates are not ABI-compatible with functions that take the delegate ptr as the first parameter. You mentioned that the problem was with the parameter order and that this should work with extern(C) functions and I think you're right. The new DIP proposes the addition of "Extension Methods" which are functions that are ABI-compatible with delegates. You define an extension method by naming the first parameter "this": struct Foo { void bar(int x) { } } void baz(ref Foo this, int x) { } Because the first parameter of baz is named this, it is an "extension method" of Foo which means it is ABI-compatible with the method bar. void delegate(int x) dg; Foo foo; dg = &foo.bar; // a normal method delegate dg(42); // calls foo.bar(42) dg = &foo.baz; // an extension method delegate dg(42); // calls baz(foo, 42); dg = &baz; // a "null delegate", unsafe code, funcptr points to the baz function, but ptr is null dg(42); // calls baz(null, 42);One small tweak is that `this` should act as a storage class instead of the user having to name the parameter `this`. This is https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp
Apr 24 2017
On Monday, 24 April 2017 at 19:19:27 UTC, Meta wrote:On Monday, 24 April 2017 at 15:47:14 UTC, Jonathan Marler wrote:initial thought. The one advantage I saw with naming the parameter "this" was that it produces more "refactorable" code. If the first parameter of a delegateable function is a reference to a struct or a class, then you could move the function inside the struct/class, take out the first parameter and the code will work as a member function with no changes since the "this" keyword will be referring to the same object in both cases. But it's not a big deal, either syntax works fine in my opinion.I've added a DIP for this (https://github.com/dlang/DIPs/pull/61). At first I first thought that all we needed was to add semantics to take the address of a UFCS-style call, but after messing around with your example I realized that delegates are not ABI-compatible with functions that take the delegate ptr as the first parameter. You mentioned that the problem was with the parameter order and that this should work with extern(C) functions and I think you're right. The new DIP proposes the addition of "Extension Methods" which are functions that are ABI-compatible with delegates. You define an extension method by naming the first parameter "this": struct Foo { void bar(int x) { } } void baz(ref Foo this, int x) { } Because the first parameter of baz is named this, it is an "extension method" of Foo which means it is ABI-compatible with the method bar. void delegate(int x) dg; Foo foo; dg = &foo.bar; // a normal method delegate dg(42); // calls foo.bar(42) dg = &foo.baz; // an extension method delegate dg(42); // calls baz(foo, 42); dg = &baz; // a "null delegate", unsafe code, funcptr points to the baz function, but ptr is null dg(42); // calls baz(null, 42);One small tweak is that `this` should act as a storage class instead of the user having to name the parameter `this`. This https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp
Apr 24 2017