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
Mon Jan 23 11:24:41 UTC 2023


On Friday, 20 January 2023 at 20:28:52 UTC, Walter Bright wrote:
> On 1/20/2023 3:49 AM, Quirin Schroll wrote:
>> 1. `process` cannot be virtual.
>
> Virtual functions are meant to be overridden, meaning their 
> attributes are inherited with covariant and contravariant 
> rules. This is incompatible with attribute inference.
>
>> 2. the argument bound to `callback` cannot have its parameter 
>> types inferred.
>
> The version of this I posted can.

TL;DR: You can infer
_either_ parameter types of callbacks
_or_ attributes of callbacks,
but you can never infer _both._

Maybe you misunderstood what I was trying to convey.

I’m guessing you mean this version:
```d
void process()(void delegate() userData) {/*impl*/}
```

Trying 2.099 (dmd-nightly on run.dlang.org), it cannot infer 
types. Only non-templates can.

## Exhaustive Example

I’m using `opApply` because it’s (as far as I know) the only 
callback pattern mentioned in the spec and it’s by far the most 
restricted. If `opApply` works, it works with simpler cases, too.

```d
struct S1
{
     int opApply     (scope int delegate(string)       callback)
     { return callback(""); }
}
struct S2
{
     int opApply     (scope int delegate(string) @safe callback) 
@safe
     { return callback(""); }
}
struct S3
{
     int opApply()   (scope int delegate(string)       callback)
     { return callback(""); }
}
struct S4
{
     int opApply(DG :       int delegate(string))(DG   callback)
     { return callback(""); }
}
struct S5
{
     int opApply(DG                       )(DG         callback)
     { return callback(""); }
}

void main() @safe
{
     foreach (x; S1()) { } // Error: `@safe` function `D main` 
cannot call
                           //        `@system` function 
`onlineapp.S1.opApply`
     foreach (x; S2()) { } // OK
     foreach (x; S3()) { } // Error: cannot infer type for 
`foreach` variable `x`
     foreach (x; S4()) { } // Error: cannot infer type for 
`foreach` variable `x`
     foreach (x; S5()) { } // Error: cannot infer type for 
`foreach` variable `x`


     foreach (string x; S1()) { } // Error: `@safe` function `D 
main` cannot call
                                  //`@system` function 
`onlineapp.S1.opApply`
     foreach (string x; S2()) { } // OK
     foreach (string x; S3()) { } // Error: none of the overloads 
of template
                                  // `onlineapp.S3.opApply` are 
callable using
                                  // argument types (**)
     foreach (string x; S4()) { } // Error: none of the overloads 
of template
                                  // `onlineapp.S4.opApply` are 
callable using
                                  // argument types (**)
     foreach (string x; S5()) { } // Error: template instance (++) 
error instantiating
     // (**) = `!()(int delegate(ref string __applyArg0) pure 
nothrow @nogc @safe)`
     // (++) = `onlineapp.S5.opApply!(int delegate(ref string) 
pure nothrow @nogc @safe)`

     foreach (string x; &S4().opApply!(int delegate(string) 
@safe)) { } // OK
     foreach (string x; &S5().opApply!(int delegate(string) 
@safe)) { } // OK
}
```
### Type-inferred Attempts

Failure on `S1` is due to the lack of “`@safe` relative to 
callable argument”; `S2` proves that by annotating `opApply` and 
restricting `callback` to `@safe` arguments.

Failure on `S3`, `S4`, and `S5` are due to lack of inference in 
the type-inferred cases; `S3` failing is unreasonable to some 
degree because the callback’s type does not depend on template 
arguments. The pattern in `S4` (type parameter used for the only 
argument is restricted to a delegate type) could be recognized by 
the compiler, but that would clearly be an enhancement and not a 
bug. That `S5` fails is to be expected. Information about the 
types (even arity) of delegate would have to be inferred from the 
body of `opApply`.

### Explicit-type Attempts

(No change by providing a type: Failure on `S1` is due to the 
lack of “`@safe` relative to callable argument”; `S2` proves that 
by annotating `opApply` and restricting `callback` to `@safe` 
arguments.)

I’d have expected `S3` to fail because the function won’t ever be 
inferred `@safe` because the callback is not restricted to 
`@safe`.
`S4` and `S5` should work, but don’t. The compiler attempts to 
instantiate them with an inappropriate delegate type: `int 
delegate(ref string) @…`. This is a bug. For every argument, 
unless the call-site uses `ref` on the argument, the compiler 
must try a delegate type without `ref`; for *n* arguments, this 
can lead to 2*ⁿ* attempts; this is by nature, it cannot be 
helped, however, if non-`ref` ones are tried first, it’s likely 
they succeed on the first attempt. This can be seen when you 
instantiate `opApply` explicitly.


More information about the Digitalmars-d mailing list