www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Alternatives to extern(delegate) (DIP 1011)

reply Jonathan Marler <johnnymarler gmail.com> writes:
Andrei suggests we take a closer look at alternatives to DIP 1011 
(extern(delegate)) that can be implemented in a library.  In the 
past I've failed to come up with anything good, however, my last 
attempt seemed to be less horrible than before.  I'm inviting 
anyone to view/modify my feeble attempt at a solution here 
https://github.com/marler8997/externdelegate

A good library solution would be great but my current solution 
has problems.  It doesn't really support template parameters yet 
and I'm not sure if it can be solved in the general case without 
pulling in a fair chunk of the language grammar into the library. 
Assuming that can be fixed, the bigger concern is that the API to 
define a "delegate function" looks very awkward.  It provides a 
template mixin that you can use to create a delegate function by 
passing in your function definition as a string.

With the current solution I believe its very unlikely that 
applications would use the library. Keep in mind that this 
feature is something that a library could use on most or all of 
it's functions.  If it has to use such an awkward syntax it's 
highly unlikely it would be used at that scale.  Not to mention 
that when you start pushing the limits of the language like this 
you almost always run into bugs and end up having to go with a 
different solution.  Also I haven't measured it but I'm almost 
certain this would greatly increase compile time as more 
functions start using it.
Oct 02
parent Jonathan Marler <johnnymarler gmail.com> writes:
On Monday, 2 October 2017 at 07:48:54 UTC, Jonathan Marler wrote:
 Andrei suggests we take a closer look at alternatives to DIP 
 1011 (extern(delegate)) that can be implemented in a library.  
 In the past I've failed to come up with anything good, however, 
 my last attempt seemed to be less horrible than before.  I'm 
 inviting anyone to view/modify my feeble attempt at a solution 
 here https://github.com/marler8997/externdelegate

 A good library solution would be great but my current solution 
 has problems.  It doesn't really support template parameters 
 yet and I'm not sure if it can be solved in the general case 
 without pulling in a fair chunk of the language grammar into 
 the library. Assuming that can be fixed, the bigger concern is 
 that the API to define a "delegate function" looks very 
 awkward.  It provides a template mixin that you can use to 
 create a delegate function by passing in your function 
 definition as a string.

 With the current solution I believe its very unlikely that 
 applications would use the library. Keep in mind that this 
 feature is something that a library could use on most or all of 
 it's functions.  If it has to use such an awkward syntax it's 
 highly unlikely it would be used at that scale.  Not to mention 
 that when you start pushing the limits of the language like 
 this you almost always run into bugs and end up having to go 
 with a different solution.  Also I haven't measured it but I'm 
 almost certain this would greatly increase compile time as more 
 functions start using it.
I've improved the solution. I've gotten templates to work, however, template parameter deduction won't work because I'm currently defining the delegate functions as structs. I'm including a bit of code to demonstrate the solution. The example will demonstrate how to define a "delegate function" that uses a File object for it's context. The function is called "importantWriteln" which simply calls writeln with a prefix of "Important: ". Here's how you would define that function: mixin delegateFunctionImpl!("importantWriteln", "(T...)", "File", "file", "T args", q{ file.writeln("Important: ", args); }); This is the code that the mixin would generate: struct importantWriteln(T...) { File file; auto opCall(T args) { file.writeln("Important: ", args); } pragma(inline) static auto opCall(ref File file, T args) { return (cast(importantWriteln*)&file).opCall(args); } // NOTE: this doesn't quite work yet if there are template parameters pragma(inline) static auto createDelegate(T...)(ref File file) { return &(cast(importantWriteln*)&file).opCall; } } And here's how you would use it: // call like a normal function importantWriteln!(string,string)(stdout, "Hello, ", "World!"); // NOTE: template type deduction doesn't work since importantWriteln is a struct // call like a delegate auto dg = importantWriteln!(string,string).createDelegate(stdout); dg("Hello, ", "again"); The worst part about this solution is how you define the function. The way I evaluate the solution is I think about ALL the functions in phobos that could use this feature (most functions that would normally be called using UFCS are good candidates) then think about whether I could create a pull request to make them all delegate functions. Given this solution, I don't think that it would be accepted.
Oct 03