Alternatives to extern(delegate) (DIP 1011)

Jonathan Marler johnnymarler at gmail.com
Tue Oct 3 15:38:34 UTC 2017


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.


More information about the Digitalmars-d mailing list