Jump to page: 1 2
Thread overview
Mixin template parameter overloading bug?
Jun 14
monkyyy
Jun 14
monkyyy
Jun 14
monkyyy
Jun 15
monkyyy
Jun 15
Monkyyy
June 14

The simplest code that shows the issue:

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:

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:

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?

June 14

On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:

>

The simplest code that shows the issue:

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:

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:

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:

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.

June 14

On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
Simplified test case a bit more.
This works:

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?

June 14

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:

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.

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;
}
June 14

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:

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.

June 14

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:

>

On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:
Simplified test case a bit more.
This works:

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.

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;
}

Modified your example a bit.
This works:

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:

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();
}
June 14

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:

>

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:

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.

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;
}

Modified your example a bit.
This works:

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:

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();
}
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

June 14

On Saturday, 14 June 2025 at 03:17:09 UTC, monkyyy wrote:

>
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

June 14

On Saturday, 14 June 2025 at 00:02:32 UTC, Andrey Zherikov wrote:

>

The simplest code that shows the issue:

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:

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:

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:

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

June 15

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.

-Steve

theres correct ambiguity errors when the return types are well typed; the code was wierd but I confirm theres a bug in here

« First   ‹ Prev
1 2