Jump to page: 1 2
Thread overview
Mixin template parameter overloading bug?
Jun 14
monkyyy
Jun 14
monkyyy
Jun 14
monkyyy
Jun 15
monkyyy
6 days ago
Monkyyy
6 days ago
Manfred Nowak
4 days ago
Nick Treleaven
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