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