www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How are delegate attributes in fn signature inferred?

reply wjoe <invalid example.com> writes:
Hello,

Consider this example:
```d
module foo;

import std.stdio;
import std.algorithm;
import std.traits;
import std.range;

void print(R)(R r) {
   static assert(isIterable!R);
   r.each!writeln;
}

auto construct(R)(R r, ElementType!R delegate(ulong i) fn) {
   static assert(isIterable!R && hasAssignableElements!R);
   ulong i = 1;
   r.each!((ref e) => e = fn(i));
   return r;
}

unittest {
   int[] i; i.length = 4;
   i.construct((ulong i) {return cast(int)(i+i);}).print;
}
```

```shell
 dmd -unittest -main foo.d
Error: template 'foo.construct' cannot deduce function from argument types '!()(int[], int function(ulong i) pure nothrow nogc safe)', candidates are: 'construct(R)(R r, ElementType!R delegate(ulong i) fn)' ``` Where's **pure nothrow nogc safe** coming from? Also, why is *(ulong i) {return cast(int)(i+i);}* passed as a function? The error message for passing a delegate is the same except with *function* substituted for *delegate*.
May 23 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Monday, 23 May 2022 at 13:44:53 UTC, wjoe wrote:
   i.construct((ulong i) {return cast(int)(i+i);}).print;
You can actually make this work with `construct!(int[])` rather than plain `construct`. This is a (really annoying) deficiency in dmd's implementation. (that sdc solved btw proving it can be done just dmd never bothered)
 Where's **pure nothrow  nogc  safe** coming from?
That's because it is a delegate literal, so it automatically figured out the tightest thing that works (this is also why it came as `function` instead of `delegate`, since it doesn't use any local variables from the enclosing function, it doesn't need the delegate pointer either). But all those implicitly convert away so it doesn't really matter. The type system allows this, just the crappy implementation can't handle inferring that R when it is mentioned both as R r *and* ElementType!R - the stupid compiler sees ElementType!R and bails out. Thus why you have to help it by telling the type when instantiating it i.construct!(int[])((ulong i) {return cast(int)(i+i);}).print;
May 23 2022
parent wjoe <invalid example.com> writes:
On Monday, 23 May 2022 at 13:53:02 UTC, Adam D Ruppe wrote:
 On Monday, 23 May 2022 at 13:44:53 UTC, wjoe wrote:
   [...]
You can actually make this work with `construct!(int[])` rather than plain `construct`. This is a (really annoying) deficiency in dmd's implementation. (that sdc solved btw proving it can be done just dmd never bothered) [...]
I see. I figured the issue was an attribute mismatch. Thanks for the explanation. Very much appreciated!
May 23 2022