www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - 2 Templates Issues (possibly bugs)

reply John Kiro <johnkirollos yahoo.com> writes:
Hello there

I've been experimenting with templates & template mixins, and I have some
questions & notes, here are they one by one:

1- I define a template like this:

template Template1(T, alias Var, alias Func)
{
	T abc = Func();		//OK.
	T xyz = Var;		//#1 Error: non-constant expression i1
	//Question 1: Why do I have this error?
}

The above error is issued in case I instantiate the template like this for ex:

	Template1!(int, i1, Func1).abc = 3;
Or
	Template1!(int, i1, Func1).xyz = 3;


No error is issued in case I instantiate it using template mixin:

	mixin Template1!(int, i1, Func1);


The normal instantiation works only in case the template is defined like this:

template Template2(T, alias TFunc1, alias TFunc2)
{
	T var1 = TFunc1();
	T var2 = TFunc2();
}

I.e. both are aliases to functions, not variables. So is this a bug?

Note: I used 2 aliases in the above templates, but the behavior is general
(i.e. even if template has only 1 alias)


2- Let's define 2 functions to be used with the previous template (template2):

	int Func1()
	{
		return 100;
	}

	int Func2()
	{
		return 200;
	}

Now the next instantiation fails:

  Template2!(int,Func1,Func2).var1;	//Error: var has no effect in expression
(var1)

The next one succeeds:

  Template2!(int,Func1,Func2).var1=10;

Next one succeeds as well (even if the instance is not defined before it):	

  writefln("var1 = ",Template2!(int,Func1,Func2).var1);	//value is 100 (as
returned by Func1() )
  Template2!(int,Func1,Func2).var1+=30;	//value is now 130
  

The question here is why the 1st one fails?

Also I see a confusion in the expression "Template2!(int,Func1,Func2).var1",
it's sometimes equivalent to variable declaration (as in the previous
writefln), and sometimes it's equivalent to a symbol (as in the "+=30"
statement).. I hope this note would be added to the documentation.

Regards
John
Oct 07 2007
parent reply BCS <ao pathlink.com> writes:
Reply to John,

 Hello there
 
 I've been experimenting with templates & template mixins, and I have
 some questions & notes, here are they one by one:
 
 1- I define a template like this:
 
 template Template1(T, alias Var, alias Func)
 {
 T abc = Func();		//OK.
 T xyz = Var;		//#1 Error: non-constant expression i1
 //Question 1: Why do I have this error?
 }
 The above error is issued in case I instantiate the template like this
 for ex:
 
 Template1!(int, i1, Func1).abc = 3;
 Or
 Template1!(int, i1, Func1).xyz = 3;

what is i1 in this case.
 2- Let's define 2 functions to be used with the previous template
 (template2):
 
 int Func1()
 {
 return 100;
 }
 int Func2()
 {
 return 200;
 }
 Now the next instantiation fails:
 
 Template2!(int,Func1,Func2).var1;	//Error: var has no effect in
 expression (var1)

that is correct, referencing the variable var1 but not using it for anything has no effect and is disallowed. The template you defined contains two global variables that are initialized with the return from two function that are passed in. The two issues you mention may be related. What I think is happening is that the initializer for a variable must be a constant. Due to compile time function evaluation (CTFE) the trivial function you used get converted to there return values. If I had to guess, I'd say that the "i1" from above is a non trivial function that can't be run through CTFE.
 
 The next one succeeds:
 
 Template2!(int,Func1,Func2).var1=10;
 
 Next one succeeds as well (even if the instance is not defined before
 it):
 
 writefln("var1 = ",Template2!(int,Func1,Func2).var1);	//value is 100
 (as returned by Func1() )
 Template2!(int,Func1,Func2).var1+=30;	//value is now 130
 The question here is why the 1st one fails?
 
 Also I see a confusion in the expression
 "Template2!(int,Func1,Func2).var1", it's sometimes equivalent to
 variable declaration (as in the previous writefln), and sometimes it's
 equivalent to a symbol (as in the "+=30" statement).. I hope this note
 would be added to the documentation.

as noted above, the expression "Template2!(int,Func1,Func2).var1" is a symbol in all cases. it is actually a reference to a global variable declared in the template. I hope that helps, If not, please do ask more questions.
 
 Regards
 John

Oct 07 2007
parent reply John Kiro <johnkirollos yahoo.com> writes:
Thanks BCS,

I still have questions below..

BCS Wrote:

 Reply to John,
 
 Hello there
 
 I've been experimenting with templates & template mixins, and I have
 some questions & notes, here are they one by one:
 
 1- I define a template like this:
 
 template Template1(T, alias Var, alias Func)
 {
 T abc = Func();		//OK.
 T xyz = Var;		//#1 Error: non-constant expression i1
 //Question 1: Why do I have this error?
 }
 The above error is issued in case I instantiate the template like this
 for ex:
 
 Template1!(int, i1, Func1).abc = 3;
 Or
 Template1!(int, i1, Func1).xyz = 3;

what is i1 in this case.

int i1=900;
 2- Let's define 2 functions to be used with the previous template
 (template2):
 
 template Template2(T, alias TFunc1, alias TFunc2)
 {
 	T var1 = TFunc1();
 	T var2 = TFunc2();
 }


 int Func1()
 {
 return 100;
 }
 int Func2()
 {
 return 200;
 }
 Now the next instantiation fails:
 
 Template2!(int,Func1,Func2).var1;	//Error: var has no effect in
 expression (var1)

that is correct, referencing the variable var1 but not using it for anything has no effect and is disallowed.

int var1 = TFunc1(); Isn't it? If so, then what's wrong with it?
 The template you defined contains two global variables that are initialized 
 with the return from two function that are passed in.
 
 The two issues you mention may be related. What I think is happening is that 
 the initializer for a variable must be a constant. Due to compile time
function 
 evaluation (CTFE) the trivial function you used get converted to there return 
 values.
 

 If I had to guess, I'd say that the "i1" from above is a non trivial function 
 that can't be run through CTFE. 
 

Strangely, adding a writefln() call inside Func2() doesn't cause any error like this, although this call cannot be done in compile-time!
 
 
 The next one succeeds:
 
 Template2!(int,Func1,Func2).var1=10;
 
 Next one succeeds as well (even if the instance is not defined before
 it):
 
 writefln("var1 = ",Template2!(int,Func1,Func2).var1);	//value is 100
 (as returned by Func1() )
 Template2!(int,Func1,Func2).var1+=30;	//value is now 130
 The question here is why the 1st one fails?
 
 Also I see a confusion in the expression
 "Template2!(int,Func1,Func2).var1", it's sometimes equivalent to
 variable declaration (as in the previous writefln), and sometimes it's
 equivalent to a symbol (as in the "+=30" statement).. I hope this note
 would be added to the documentation.

as noted above, the expression "Template2!(int,Func1,Func2).var1" is a symbol in all cases. it is actually a reference to a global variable declared in the template.

A global var would be declared if I instantiate the template or use a template mixin.
 I hope that helps, If not, please do ask more questions.
 

 
 Regards
 John


John
Oct 07 2007
parent reply BCS <ao pathlink.com> writes:
Reply to John,

 Thanks BCS,
 
 I still have questions below..
 
 BCS Wrote:
 
 template Template1(T, alias Var, alias Func)
 {
 T abc = Func();		//OK.
 T xyz = Var;		//#1 Error: non-constant expression i1
 //Question 1: Why do I have this error?
 }
 The above error is issued in case I instantiate the template like
 this
 for ex:
 Template1!(int, i1, Func1).abc = 3;
 Or
 Template1!(int, i1, Func1).xyz = 3;


int i1=900;

In that case the problem is that i1 is not a constant expression. A variable declared inside of a template in many respects is like a global variable, or a static variable in a struct. As such, if you declare it and initialize it at the same time then the thing used to initialize it must be a constant. In your case i1 isn't.
 that is correct, referencing the variable var1 but not using it for
 anything has no effect and is disallowed.
 

equivalent to int var1 = TFunc1(); Isn't it? If so, then what's wrong with it?

In D a template is a scope. Everything inside of it is instanced once for each set of arguments that the template is used with. As such Template!(int,Func1,Func2).var1 is just another variable. Ignoring the template stuff for a moment what you get is approximately the same as this: // At the location Template1 is defined int var1 = TFunk1(); ... // At the location Template1 is used. var1; If you want to plop down an instance of everything in the template in the current scope, then you need to use a mixin.
 The template you defined contains two global variables that are
 initialized with the return from two function that are passed in.
 
 The two issues you mention may be related. What I think is happening
 is that the initializer for a variable must be a constant. Due to
 compile time function evaluation (CTFE) the trivial function you used
 get converted to there return values.
 

documentation that the initialization must be with a constant.

I could be mistaken, but I think the only case where a con constant finalization is allowed is for local variables in a function (this is related to the fact that executable code is only allowed in a function). As noted above, the declaration inside a template are effectively global and as such are not inside a function, thus they need constants if they are initialized.
 If I had to guess, I'd say that the "i1" from above is a non trivial
 function that can't be run through CTFE.
 

the error: "Error: cannot evaluate Func2() at compile time", thus confirming your thoughts. But as I said, why isn't this allowed, is it a template restriction? Where is it stated in the document?

see above.
 
 Strangely, adding a writefln() call inside Func2() doesn't cause any
 error like this, although this call cannot be done in compile-time!
 

Unless something else is happening that is a bug. Did it actually compile and run with that version? If it gave another error, then it might not have gotten that far. Get everything else sorted out and if writefln still works, then you have found a bug.
 as noted above, the expression "Template2!(int,Func1,Func2).var1" is
 a symbol in all cases. it is actually a reference to a global
 variable declared in the template.
 

doesn't define any variables, it's same as class definition. No object is defined until the class is instantiated. A global var would be declared if I instantiate the template or use a template mixin.

I think I covered this above, but to be sure... As you note, a template definition doesn't define any variables. However when you uses a template (e.i. Template1(Type, Foo, Bar) ) then you have defined the set of symbols described inside the template. If you then use the template again with different arguments, then you define another set of symbols. It is interesting to note that you can declare a template with a non const variable in it and then reference the same variable from different locations. template T(char[] name) { int i=0; } void main() { T!("hello").i = 5; T!("world").i = 7; T!("hello").i --; T!("world").i ++; writef("%d, %d\n", T!("hello").i, T!("world").i); // should print "4, 8" } It seems that you are thinking of template just slightly different than D uses them. I'm guessing that this is coming from using template in some other language (C++ perhaps?) that has a slightly different take on them.
Oct 07 2007
parent John Kiro <johnkirollos yahoo.com> writes:
Thanks again BCS,

It's clearer now. I found the part in the documentation equivalent to what you
explained:
In Templates page: "Template Instantances are always performed in the scope of
where the TemplateDeclaration is declared..."

And in Template Mixins page: "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."

So although I instantiated the template inside the main() body, the instances
(Which are variables in my case) were actually instantiated in the template
scope (which is global), that's why initialization with non-constant was
refused.

Using template mixins solves this problem. However, what I was trying to
achieve is to have different variables based on the function alias passed as
argument. I can't achieve this using template mixins as defining more than 1
mixin would try to create several variables having the same name, =>
compilation error. Anyway, I'll search for another method to achieve my aim.

I'll also check the writefln issue to see if there is indeed a bug.

And thanks for the last example.. interesting indeed!

Regards,
John

BCS Wrote:

 Reply to John,
 
 Thanks BCS,
 
 I still have questions below..
 
 BCS Wrote:
 
 template Template1(T, alias Var, alias Func)
 {
 T abc = Func();		//OK.
 T xyz = Var;		//#1 Error: non-constant expression i1
 //Question 1: Why do I have this error?
 }
 The above error is issued in case I instantiate the template like
 this
 for ex:
 Template1!(int, i1, Func1).abc = 3;
 Or
 Template1!(int, i1, Func1).xyz = 3;


int i1=900;

In that case the problem is that i1 is not a constant expression. A variable declared inside of a template in many respects is like a global variable, or a static variable in a struct. As such, if you declare it and initialize it at the same time then the thing used to initialize it must be a constant. In your case i1 isn't.
 that is correct, referencing the variable var1 but not using it for
 anything has no effect and is disallowed.
 

equivalent to int var1 = TFunc1(); Isn't it? If so, then what's wrong with it?

In D a template is a scope. Everything inside of it is instanced once for each set of arguments that the template is used with. As such Template!(int,Func1,Func2).var1 is just another variable. Ignoring the template stuff for a moment what you get is approximately the same as this: // At the location Template1 is defined int var1 = TFunk1(); ... // At the location Template1 is used. var1; If you want to plop down an instance of everything in the template in the current scope, then you need to use a mixin.
 The template you defined contains two global variables that are
 initialized with the return from two function that are passed in.
 
 The two issues you mention may be related. What I think is happening
 is that the initializer for a variable must be a constant. Due to
 compile time function evaluation (CTFE) the trivial function you used
 get converted to there return values.
 

documentation that the initialization must be with a constant.

I could be mistaken, but I think the only case where a con constant finalization is allowed is for local variables in a function (this is related to the fact that executable code is only allowed in a function). As noted above, the declaration inside a template are effectively global and as such are not inside a function, thus they need constants if they are initialized.
 If I had to guess, I'd say that the "i1" from above is a non trivial
 function that can't be run through CTFE.
 

the error: "Error: cannot evaluate Func2() at compile time", thus confirming your thoughts. But as I said, why isn't this allowed, is it a template restriction? Where is it stated in the document?

see above.
 
 Strangely, adding a writefln() call inside Func2() doesn't cause any
 error like this, although this call cannot be done in compile-time!
 

Unless something else is happening that is a bug. Did it actually compile and run with that version? If it gave another error, then it might not have gotten that far. Get everything else sorted out and if writefln still works, then you have found a bug.
 as noted above, the expression "Template2!(int,Func1,Func2).var1" is
 a symbol in all cases. it is actually a reference to a global
 variable declared in the template.
 

doesn't define any variables, it's same as class definition. No object is defined until the class is instantiated. A global var would be declared if I instantiate the template or use a template mixin.

I think I covered this above, but to be sure... As you note, a template definition doesn't define any variables. However when you uses a template (e.i. Template1(Type, Foo, Bar) ) then you have defined the set of symbols described inside the template. If you then use the template again with different arguments, then you define another set of symbols. It is interesting to note that you can declare a template with a non const variable in it and then reference the same variable from different locations. template T(char[] name) { int i=0; } void main() { T!("hello").i = 5; T!("world").i = 7; T!("hello").i --; T!("world").i ++; writef("%d, %d\n", T!("hello").i, T!("world").i); // should print "4, 8" } It seems that you are thinking of template just slightly different than D uses them. I'm guessing that this is coming from using template in some other language (C++ perhaps?) that has a slightly different take on them.

Oct 09 2007