Consider:
template canon(string v) {
auto fun(alias lambda)(int x) {
return lambda(x);
}
}
alias f1 = canon!"abc".fun;
void main() {
int x = 42;
f1!(y => y + x)(1);
}
The code produces the error:
Deprecation: function `onlineapp.main.f1!((y) => y + x).fun` function requires a dual-context, which is deprecated
There is no dual context anywhere in sight. The canon template takes a compile-time string, which requires no context.
This blocks phobos versioning.
Comment #1 by kinke — 2021-11-10T14:30:58Z
AFAIK, the problem is that the alias template parameter doesn't capture the context if bound to a nested function, unlike a delegate runtime parameter. `canon!"abc".fun!<delegateLambda>` would need a hidden context runtime parameter to forward to the lambda invocation:
auto canon!"abc".fun!<lambda>(void* __lambda_context, int x) {
return <lambda>(__lambda_context, x);
}
void main() {
int x = 42;
canon!"abc".fun!(y => y + x)(<main_context>, 1);
}
Comment #2 by andrei — 2021-11-10T17:45:54Z
(In reply to kinke from comment #1)
> AFAIK, the problem is that the alias template parameter doesn't capture the
> context if bound to a nested function, unlike a delegate runtime parameter.
> `canon!"abc".fun!<delegateLambda>` would need a hidden context runtime
> parameter to forward to the lambda invocation:
>
> auto canon!"abc".fun!<lambda>(void* __lambda_context, int x) {
> return <lambda>(__lambda_context, x);
> }
>
> void main() {
> int x = 42;
> canon!"abc".fun!(y => y + x)(<main_context>, 1);
> }
Not sure I understand but hopefully it's something that can be fixed, right?
Things would be different if the template itself took an alias parameter that could be bound to a distinct context. But it being a string makes all the difference.
Also forgot to mention that this code also doesn't work but for a different reason:
template canon(string v) {
static auto fun(alias lambda)(int x) {
return lambda(x);
}
}
alias f1 = canon!"abc".fun;
void main() {
int x = 42;
f1!(y => y + x)(1);
}
Error: `static` function `onlineapp.main.f1!((y) => y + x).fun` cannot access delegate `__lambda2` in frame of function `D main`
Comment #3 by kinke — 2021-11-10T19:15:38Z
(In reply to Andrei Alexandrescu from comment #2)
> Not sure I understand but hopefully it's something that can be fixed, right?
Nevermind, that's what the compiler does for a freestanding function template. In your example with parent template instance, the current behavior seems to match that of a simple struct parent:
```
int foo(alias f)(int x) { return f(x); }
struct S {
static int staticFoo(alias f)(int x) { return f(x); }
int foo(alias f)(int x) { return f(x); }
}
void main() {
int x = 42;
int nested(int y) { return y + x; }
foo!nested(1);
// should work analogously (without dual context) but doesn't:
//S.staticFoo!nested(1);
// correctly requires dual-context:
S().foo!nested(1);
}
```
So some logic seems to be definitely off here (and surely fixable).
Comment #4 by robert.schadek — 2024-12-13T19:19:14Z