digitalmars.D.learn - Mixin template parameter overloading bug?
- Andrey Zherikov (40/40) Jun 13 The simplest code that shows the issue:
- monkyyy (22/62) Jun 13 I believe every change in compilation from (top level)
- Andrey Zherikov (8/29) Jun 13 Mixin templates and regular templates have different use cases:
- Andrey Zherikov (16/16) Jun 13 On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
- monkyyy (21/38) Jun 13 https://dlang.org/spec/template-mixin.html
- Andrey Zherikov (31/74) Jun 13 Modified your example a bit.
- monkyyy (13/91) Jun 13 ```d
- Andrey Zherikov (2/17) Jun 14 I created https://github.com/dlang/dmd/issues/21447
- Steven Schveighoffer (24/64) Jun 14 A lambda is a shortened syntax for a function literal or delegate
- monkyyy (4/11) Jun 14 theres correct ambiguity errors when the return types are well
- Nick Treleaven (16/29) Jun 15 An untyped parameter does make the literal an actual template:
- Monkyyy (5/7) Jun 15 Given it's specifically void return, and top level and it acts
- Manfred Nowak (9/14) Jun 15 Therefore in the case discussed, the code `(_){}' declares a
- Nick Treleaven (2/11) Jun 17 Yes, sorry I misread.
The simplest code that shows the issue:
```d
struct S{}
template f(void function(S) F) {}
template f(int function(S) F) {}
mixin f!((_) {});
mixin f!((_) => 0); // Error: cannot return non-void from `void`
function
// mixin f!((_) => 0);
// ^
// while looking for match for
`f!((_) => 0)`
// mixin f!((_) => 0);
```
If I swap `template f` declarations:
```d
struct S{}
template f(int function(S) F) {}
template f(void function(S) F) {}
mixin f!((_) {}); // Error: function
`onlineapp.__lambda_L8_C10(__T1)(_)` has no `return` statement,
but is expected to return a value of type `int`
// mixin f!((_) {});
// ^
// while looking for match for `f!((_)
// {
// }
// )`
// mixin f!((_) {});
// ^
mixin f!((_) => 0);
```
But if I remove `S` from template parameters, everything works:
```d
template f(int function() F) {}
template f(void function() F) {}
mixin f!(() {});
mixin f!(() => 0);
```
Is this a bug somewhere in compiler or in my code?
Jun 13
On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
The simplest code that shows the issue:
```d
struct S{}
template f(void function(S) F) {}
template f(int function(S) F) {}
mixin f!((_) {});
mixin f!((_) => 0); // Error: cannot return non-void from
`void` function
// mixin f!((_) => 0);
// ^
// while looking for match for
`f!((_) => 0)`
// mixin f!((_) => 0);
```
If I swap `template f` declarations:
```d
struct S{}
template f(int function(S) F) {}
template f(void function(S) F) {}
mixin f!((_) {}); // Error: function
`onlineapp.__lambda_L8_C10(__T1)(_)` has no `return` statement,
but is expected to return a value of type `int`
// mixin f!((_) {});
// ^
// while looking for match for `f!((_)
// {
// }
// )`
// mixin f!((_) {});
// ^
mixin f!((_) => 0);
```
But if I remove `S` from template parameters, everything works:
```d
template f(int function() F) {}
template f(void function() F) {}
mixin f!(() {});
mixin f!(() => 0);
```
Is this a bug somewhere in compiler or in my code?
I believe every change in compilation from (top level)
declaration order is considered a compiler bug
However, I see.... Allot of issues with this code, Id want to see
something near functional code around this subject; its worth
poking, but its possible every possible way to make this code
work would eliminate the pattern here
for example this compiles:
```d
import std;
struct S{}
template f(void function(S) F) {alias f=void;}
template f(int function(S) F) {alias f=int;}
unittest{
alias a=f!((_) {});
alias b=f!((_) => 0);
a.stringof.writeln;
b.stringof.writeln;
}
```
mixin templates vs declaration templates was a bad decision in my
opinion but thats old news.
Jun 13
On Saturday, 14 June 2025 at 00:26:27 UTC, monkyyy wrote:
I believe every change in compilation from (top level)
declaration order is considered a compiler bug
However, I see.... Allot of issues with this code, Id want to
see something near functional code around this subject; its
worth poking, but its possible every possible way to make this
code work would eliminate the pattern here
for example this compiles:
```d
import std;
struct S{}
template f(void function(S) F) {alias f=void;}
template f(int function(S) F) {alias f=int;}
unittest{
alias a=f!((_) {});
alias b=f!((_) => 0);
a.stringof.writeln;
b.stringof.writeln;
}
```
mixin templates vs declaration templates was a bad decision in
my opinion but thats old news.
Mixin templates and regular templates have different use cases:
the former can inject declaration on caller's site while the
latter can't.
In my case mixin template generates top-level `main()` function
but the content of the template is not important here.
Also using `alias F` as template parameter doesn't allow me to
introspect the actual type.
Jun 13
On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
Simplified test case a bit more.
This works:
```d
template f(void function(int) F) {}
template f(int function(int) F) {}
mixin f!((int _) {});
mixin f!((int _) => 0);
mixin f!((int) {});
mixin f!((int) => 0);
mixin f!((_) {});
mixin f!((_) => 0); // Error: cannot return non-void from `void`
function
```
Can anyone explain why adding type of the parameter in lambda
(`int`) makes this working?
Jun 13
On Saturday, 14 June 2025 at 01:46:31 UTC, Andrey Zherikov wrote:
On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov
wrote:
Simplified test case a bit more.
This works:
```d
template f(void function(int) F) {}
template f(int function(int) F) {}
mixin f!((int _) {});
mixin f!((int _) => 0);
mixin f!((int) {});
mixin f!((int) => 0);
mixin f!((_) {});
mixin f!((_) => 0); // Error: cannot return non-void from
`void` function
```
Can anyone explain why adding type of the parameter in lambda
(`int`) makes this working?
https://dlang.org/spec/template-mixin.html
Your still mixing syntax; mixin templates are suppose to be a
separate system according to the spec.
```d
import std;
void f(int function(int) F)(){"int".writeln;}
void f(void function(int) F)(){"void".writeln;}
unittest{
f!((_) {});
f!((_) => 0);
}
mixin template g(int function(int) F){string s1="int";}
mixin template g(void function(int) F){string s2="void";}
unittest{
mixin g!((_) {});
mixin g!((_) => 0);
s1.writeln;
s2.writeln;
}
```
Jun 13
On Saturday, 14 June 2025 at 02:10:03 UTC, monkyyy wrote:On Saturday, 14 June 2025 at 01:46:31 UTC, Andrey Zherikov wrote:Modified your example a bit. This works: ```d mixin template f(void function(int) F) { void s1() {"void".writeln; } } mixin template f(int function(int) F) { void s2() {"int".writeln; } } void main() { mixin f!((_) {}); mixin f!((_) => 0); s1(); s2(); } ``` This does not: ```d mixin template f(void function(int) F) { void s1() {"void".writeln; } } mixin template f(int function(int) F) { void s2() {"int".writeln; } } mixin f!((_) {}); mixin f!((_) => 0); // Error: cannot return non-void from `void` function void main() { s1(); s2(); } ```On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote: Simplified test case a bit more. This works: ```d template f(void function(int) F) {} template f(int function(int) F) {} mixin f!((int _) {}); mixin f!((int _) => 0); mixin f!((int) {}); mixin f!((int) => 0); mixin f!((_) {}); mixin f!((_) => 0); // Error: cannot return non-void from `void` function ``` Can anyone explain why adding type of the parameter in lambda (`int`) makes this working?https://dlang.org/spec/template-mixin.html Your still mixing syntax; mixin templates are suppose to be a separate system according to the spec. ```d import std; void f(int function(int) F)(){"int".writeln;} void f(void function(int) F)(){"void".writeln;} unittest{ f!((_) {}); f!((_) => 0); } mixin template g(int function(int) F){string s1="int";} mixin template g(void function(int) F){string s2="void";} unittest{ mixin g!((_) {}); mixin g!((_) => 0); s1.writeln; s2.writeln; } ```
Jun 13
On Saturday, 14 June 2025 at 02:16:58 UTC, Andrey Zherikov wrote:On Saturday, 14 June 2025 at 02:10:03 UTC, monkyyy wrote:```d import std; mixin template f(int function(int) F){} mixin template f(void function(int) F){unittest{"void".writeln;}} //mixin f!((_){}); //FAILS mixin template g(void function(int) F){unittest{"void".writeln;}} mixin template g(int function(int) F){} mixin g!((_){}); //works ``` this example makes it purely a compiler bug I cant escape any useful information(I tried `typeof(return)`), seems to be limited to just void return functionsOn Saturday, 14 June 2025 at 01:46:31 UTC, Andrey Zherikov wrote:Modified your example a bit. This works: ```d mixin template f(void function(int) F) { void s1() {"void".writeln; } } mixin template f(int function(int) F) { void s2() {"int".writeln; } } void main() { mixin f!((_) {}); mixin f!((_) => 0); s1(); s2(); } ``` This does not: ```d mixin template f(void function(int) F) { void s1() {"void".writeln; } } mixin template f(int function(int) F) { void s2() {"int".writeln; } } mixin f!((_) {}); mixin f!((_) => 0); // Error: cannot return non-void from `void` function void main() { s1(); s2(); } ```On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote: Simplified test case a bit more. This works: ```d template f(void function(int) F) {} template f(int function(int) F) {} mixin f!((int _) {}); mixin f!((int _) => 0); mixin f!((int) {}); mixin f!((int) => 0); mixin f!((_) {}); mixin f!((_) => 0); // Error: cannot return non-void from `void` function ``` Can anyone explain why adding type of the parameter in lambda (`int`) makes this working?https://dlang.org/spec/template-mixin.html Your still mixing syntax; mixin templates are suppose to be a separate system according to the spec. ```d import std; void f(int function(int) F)(){"int".writeln;} void f(void function(int) F)(){"void".writeln;} unittest{ f!((_) {}); f!((_) => 0); } mixin template g(int function(int) F){string s1="int";} mixin template g(void function(int) F){string s2="void";} unittest{ mixin g!((_) {}); mixin g!((_) => 0); s1.writeln; s2.writeln; } ```
Jun 13
On Saturday, 14 June 2025 at 03:17:09 UTC, monkyyy wrote:
```d
import std;
mixin template f(int function(int) F){}
mixin template f(void function(int)
F){unittest{"void".writeln;}}
//mixin f!((_){}); //FAILS
mixin template g(void function(int)
F){unittest{"void".writeln;}}
mixin template g(int function(int) F){}
mixin g!((_){}); //works
```
this example makes it purely a compiler bug
I cant escape any useful information(I tried `typeof(return)`),
seems to be limited to just void return functions
I created https://github.com/dlang/dmd/issues/21447
Jun 14
On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
The simplest code that shows the issue:
```d
struct S{}
template f(void function(S) F) {}
template f(int function(S) F) {}
mixin f!((_) {});
mixin f!((_) => 0); // Error: cannot return non-void from
`void` function
// mixin f!((_) => 0);
// ^
// while looking for match for
`f!((_) => 0)`
// mixin f!((_) => 0);
```
If I swap `template f` declarations:
```d
struct S{}
template f(int function(S) F) {}
template f(void function(S) F) {}
mixin f!((_) {}); // Error: function
`onlineapp.__lambda_L8_C10(__T1)(_)` has no `return` statement,
but is expected to return a value of type `int`
// mixin f!((_) {});
// ^
// while looking for match for `f!((_)
// {
// }
// )`
// mixin f!((_) {});
// ^
mixin f!((_) => 0);
```
But if I remove `S` from template parameters, everything works:
```d
template f(int function() F) {}
template f(void function() F) {}
mixin f!(() {});
mixin f!(() => 0);
```
Is this a bug somewhere in compiler or in my code?
A lambda is a shortened syntax for a function literal or delegate
literal.
HOWEVER, when you do not give the parameters types, the lambda
becomes a template! Well, not actually a template, but a
quasi-template.
If you add types to your lambda, then the compiler can figure it
out:
```d
mixin f!((S _) {});
mixin f!((S _) => 0);
```
These are now no longer templates, but instead concrete function
literals.
BIG NOTE: just putting `S` doesn't work, because `S` becomes the
parameter name in that case. This is why `int` might work there
-- `int` cannot be a parameter name.
If I had to guess, I think the compiler is not able to exactly
deduce what form your lambda should be instantiated with. I think
it's picking the first form it sees.
I think if anything, the error message is really weird. I'd
expect possibly an ambiguity error. But I'm not sure the language
is supposed to handle your case.
-Steve
Jun 14
On Saturday, 14 June 2025 at 23:49:19 UTC, Steven Schveighoffer wrote:If I had to guess, I think the compiler is not able to exactly deduce what form your lambda should be instantiated with. I think it's picking the first form it sees. I think if anything, the error message is really weird. I'd expect possibly an ambiguity error. But I'm not sure the language is supposed to handle your case. -Stevetheres correct ambiguity errors when the return types are well typed; the code was wierd but I confirm theres a bug in here
Jun 14
On Saturday, 14 June 2025 at 23:49:19 UTC, Steven Schveighoffer wrote:A lambda is a shortened syntax for a function literal or delegate literal. HOWEVER, when you do not give the parameters types, the lambda becomes a template! Well, not actually a template, but a quasi-template.An untyped parameter does make the literal an actual template: ```d pragma(msg, __traits(isTemplate, (x) {})); // true ``` It can be instantiated with a type parameter. https://dlang.org/spec/expression.html#function-literal-aliasIf you add types to your lambda, then the compiler can figure it out: ```d mixin f!((S _) {}); mixin f!((S _) => 0); ``` These are now no longer templates, but instead concrete function literals.When there are no parameters, a literal is not a template: ```d pragma(msg, __traits(isTemplate, () {})); // false alias f = () {}; pragma(msg, is(typeof(*f) == function)); // true ``` So I think there must be another reason why your unary literals work.
Jun 15
On Sunday, 15 June 2025 at 10:51:37 UTC, Nick Treleaven wrote:So I think there must be another reason why your unary literals work.Given it's specifically void return, and top level and it acts like it matches the first return, I expect that void is incorrectly being considered a invalid return type thru 1 very specific pathway of the compiler
Jun 15
On Sunday, 15 June 2025 at 10:51:37 UTC, Nick Treleaven wrote:
An untyped parameter does make the literal an actual template:
```d
pragma(msg, __traits(isTemplate, (x) {})); // true
```
It can be instantiated with a type parameter.
Therefore in the case discussed, the code `(_){}' declares a
template. This template is used as an actual parameter to a
parameterized mixin.
If used and in general, templates must be instantiated and the
instantiatons stored for later use.
It seems, that for a parameterized mixin those actual
instantiatons are not deleted when they do not conform with the
formal parameter of the mixin.
Jun 15
On Sunday, 15 June 2025 at 16:14:28 UTC, Manfred Nowak wrote:On Sunday, 15 June 2025 at 10:51:37 UTC, Nick Treleaven wrote:Yes, sorry I misread.An untyped parameter does make the literal an actual template: ```d pragma(msg, __traits(isTemplate, (x) {})); // true ``` It can be instantiated with a type parameter.Therefore in the case discussed, the code `(_){}' declares a template. This template is used as an actual parameter to a parameterized mixin.
Jun 17









Andrey Zherikov <andrey.zherikov gmail.com> 