Thread overview
Using template mixin, with or without mixin ?
Apr 07, 2017
biocyberman
Apr 07, 2017
Ali Çehreli
Apr 08, 2017
biocyberman
Apr 08, 2017
Meta
Apr 08, 2017
ag0aep6g
Apr 09, 2017
Meta
Apr 09, 2017
ag0aep6g
April 07, 2017
I want to use mixin to generate function in-place. In template declaration, I can see 'mixin' keyword is optional. Is it true? What is the difference and when I must use one way over another?

This is my program:

// This works with and without 'mixin' attribute.
mixin template funcgen(T, U){

  T func1(string pr2){
    writeln("Func1: ", pr2);
  }
  U func2(string pr3){
    writeln("Func2: ", pr3);
  }

}

int main(string[] args){

  mixin funcgen!(void, void);
  func1("func1");
  func2("func2");
  return 0;

}
April 07, 2017
On 04/07/2017 04:47 PM, biocyberman wrote:
> I want to use mixin to generate function in-place. In template
> declaration, I can see 'mixin' keyword is optional. Is it true? What is
> the difference and when I must use one way over another?
>
> This is my program:
>
> // This works with and without 'mixin' attribute.
> mixin template funcgen(T, U){
>
>   T func1(string pr2){
>     writeln("Func1: ", pr2);
>   }
>   U func2(string pr3){
>     writeln("Func2: ", pr3);
>   }
>
> }
>
> int main(string[] args){
>
>   mixin funcgen!(void, void);
>   func1("func1");
>   func2("func2");
>   return 0;
>
> }

The difference is that you can't use funcgen as a regular template:

    funcgen!(void, void);

Error: template instance funcgen!(void, void) mixin templates are not regular templates

I think it's good practice to use 'mixin template' if it's intended to be so.

Ali

April 08, 2017
On Friday, 7 April 2017 at 23:53:12 UTC, Ali Çehreli wrote:
>
> The difference is that you can't use funcgen as a regular template:
>
>     funcgen!(void, void);
>
> Error: template instance funcgen!(void, void) mixin templates are not regular templates
>
> I think it's good practice to use 'mixin template' if it's intended to be so.
>
> Ali

Thanks for a very concise answer.

April 08, 2017
On Saturday, 8 April 2017 at 09:47:07 UTC, biocyberman wrote:
> On Friday, 7 April 2017 at 23:53:12 UTC, Ali Çehreli wrote:
>>
>> The difference is that you can't use funcgen as a regular template:
>>
>>     funcgen!(void, void);
>>
>> Error: template instance funcgen!(void, void) mixin templates are not regular templates
>>
>> I think it's good practice to use 'mixin template' if it's intended to be so.
>>
>> Ali
>
> Thanks for a very concise answer.

In addition to Ali's answer, mixin templates do their symbol looking at the instantiation site, while regular templates do it at the declaration site. Example:

enum a = 0;

template test1()
{
	enum b1 = a; //Okay, a is in scope at the declaration site
	//enum c = d1; Error: undefined identifier d1
}

mixin template test2()
{
	enum b2 = a; //Okay, a is in scope at the declaration site
	enum c = d1; //Okay, d1 is in scope at the *instantiation* site
	//enum e = d2; Error: undefined identifier d2
}

void main()
{
	enum d1 = 0; //<--d1 is declared here
	mixin test1!();
	mixin test2!(); //<--so it is in scope here
	enum d2 = 0; //d2 was not declared before test2 was mixed in
                     //so it is not in scope for test2
}
April 09, 2017
On 04/08/2017 11:59 PM, Meta wrote:
> enum a = 0;
>
> template test1()
> {
>     enum b1 = a; //Okay, a is in scope at the declaration site
>     //enum c = d1; Error: undefined identifier d1

This line works just fine, actually. There's really no difference between a normal template and a mixin template when you use it in a mixin.

> }
>
> mixin template test2()
> {
>     enum b2 = a; //Okay, a is in scope at the declaration site
>     enum c = d1; //Okay, d1 is in scope at the *instantiation* site
>     //enum e = d2; Error: undefined identifier d2
> }
>
> void main()
> {
>     enum d1 = 0; //<--d1 is declared here
>     mixin test1!();
>     mixin test2!(); //<--so it is in scope here
>     enum d2 = 0; //d2 was not declared before test2 was mixed in
>                      //so it is not in scope for test2
> }

April 09, 2017
On Saturday, 8 April 2017 at 22:37:18 UTC, ag0aep6g wrote:
> On 04/08/2017 11:59 PM, Meta wrote:
>> enum a = 0;
>>
>> template test1()
>> {
>>     enum b1 = a; //Okay, a is in scope at the declaration site
>>     //enum c = d1; Error: undefined identifier d1
>
> This line works just fine, actually. There's really no difference between a normal template and a mixin template when you use it in a mixin.
>
>> }
>>
>> mixin template test2()
>> {
>>     enum b2 = a; //Okay, a is in scope at the declaration site
>>     enum c = d1; //Okay, d1 is in scope at the *instantiation* site
>>     //enum e = d2; Error: undefined identifier d2
>> }
>>
>> void main()
>> {
>>     enum d1 = 0; //<--d1 is declared here
>>     mixin test1!();
>>     mixin test2!(); //<--so it is in scope here
>>     enum d2 = 0; //d2 was not declared before test2 was mixed in
>>                      //so it is not in scope for test2
>> }

Hmm, you're right, but this is not how it is supposed to behave according to the documentation.

https://dlang.org/spec/template-mixin.html
April 09, 2017
On 04/09/2017 07:44 AM, Meta wrote:
> On Saturday, 8 April 2017 at 22:37:18 UTC, ag0aep6g wrote:
[...]
>> This line works just fine, actually. There's really no difference
>> between a normal template and a mixin template when you use it in a
>> mixin.
[...]
> Hmm, you're right, but this is not how it is supposed to behave
> according to the documentation.
>
> https://dlang.org/spec/template-mixin.html

The most fitting sentence I can find there is this: "Unlike a template instantiation, a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined."

But that doesn't compare the different kinds of declarations. It compares the invocations: "template instantiation" vs "template mixin".

A "template instantiation" is, of course, something like `foo!()`. But the definition of a "template mixin" [1] may be a bit surprising. `mixin bar!()` is a "template mixin". It isn't and doesn't contain a "template instantiation". It's an independent language construct.

Also note that the spec says: "The MixinTemplateName refers to a TemplateDeclaration." That is, MixinTemplateName is not restricted to refer to a TemplateMixinDeclaration.

Actually, being pedantic, the spec doesn't say that you can use the name of a TemplateMixinDeclaration. Seems to be a minor oversight. PR:
https://github.com/dlang/dlang.org/pull/1627


[1] https://dlang.org/spec/template-mixin.html#TemplateMixin