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