On Friday, 20 January 2023 at 20:28:52 UTC, Walter Bright wrote:
>On 1/20/2023 3:49 AM, Quirin Schroll wrote:
>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.
>- 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:
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.
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.