Trying to use Mir ion, its a perfect example of the failure of D's attribute system
Quirin Schroll
qs.il.paperinik at gmail.com
Fri Jan 20 11:49:42 UTC 2023
On Friday, 20 January 2023 at 03:41:02 UTC, Walter Bright wrote:
> On 1/19/2023 7:19 PM, H. S. Teoh wrote:
>> This is a flaw in the language: there is no way to express that
>> `process`'s attributes inherit from the passed-in delegate.
>> This has
>> been a pain point for years.
>
> void process()(void delegate() userData) {}
Er, no. The template `process` will be inferred `@system thorw
@gc impure` because the delegate is annotated `@system thorw @gc
impure` implicitly – unless you don’t actually call it. The
correct version is this:
```D
void process(DG : void delegate())(DG callback) { callback(); }
```
This has two drawbacks:
1. `process` cannot be virtual.
2. the argument bound to `callback` cannot have its parameter
types inferred.
By 2. I mean the little more interesting example when the
delegate takes parameters, say `int`:
```D
/*A*/ void process(void delegate(int) callback) { callback(); }
/*B*/ void process(DG : void delegate(int))(DG callback) {
callback(); }
```
(The constraint is optional, but useful.)
For version A, when `process` is called, like `process((x){})`,
the compiler can statically infer that `x` is of type `int`. For
version B, it cannot, but it does not matter practically for
functions like `process`, however it does matter for `opApply`
because programmers using a `foreach` loop really want the type
of the iteration variable inferred (especially in meta
programming); this inference only works when `opApply` is not a
template. `opApply` may still be a template instance (or an alias
to a template instance), which we can put to use. The shortest I
could get to:
```d
import std.meta : AliasSeq;
import std.traits : SetFunctionAttributes, functionLinkage,
functionAttributes, FunctionAttribute;
template WithAnyCombinationOfAttributes(DG)
{
alias WithAnyCombinationOfAttributes = AliasSeq!();
static foreach (safety; [ FunctionAttribute.system,
FunctionAttribute.safe ])
static foreach (purity; [ FunctionAttribute.none,
FunctionAttribute.pure_ ])
static foreach (gcness; [ FunctionAttribute.none,
FunctionAttribute.nogc ])
static foreach (exness; [ FunctionAttribute.none,
FunctionAttribute.nothrow_ ])
{
WithAnyCombinationOfAttributes =
AliasSeq!(WithAnyCombinationOfAttributes,
SetFunctionAttributes!(DG, functionLinkage!DG,
(functionAttributes!DG & ~ FunctionAttribute.system) | safety |
purity | gcness | exness));
}
}
mixin template opApplyFromImpl(alias impl, protoDG, alias
_WithAnyCombinationOfAttributes = WithAnyCombinationOfAttributes)
{
static foreach (DG; _WithAnyCombinationOfAttributes!protoDG)
alias opApply = impl!DG;
}
```
You can find the code in action
[here](https://wandbox.org/permlink/rqasKlZTaspJ9gnI). In my
opinion, something like this should be in Phobos.
The drawbacks are lots of template instantiations and that it
always generates 16 overloads.
More information about the Digitalmars-d
mailing list