www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What the heck is wrong with CTFE's?

reply "JS" <js.mdnq gmail.com> writes:
The following code inserts properties for each type,

auto name = "Value"~((i == 0) ? "" : to!string(i++));

always as the i == 0 evaluate to true.


My question is, why the heck is it so hard to use basic 
programming structs inside CTFE's? I know that CTFE's have to 
work at run time also, so there is a limitation, but:

1. obviously ints work because the code below works with i as a 
counter but we can't do a simple compare on it... this seems like 
a bug.

2. foreach can be used but a simple for loop can't... makes no 
sense.

I know what the average response is going to be but hopefully 
someone will surprise me with some useful.



mixin template PropertyBuilder(T...)
{
	template _(TT...)
	{
		static string eval()
		{
			string s;
			pragma(msg, TT);
			int i = 0;
			foreach(t; TT)
			{
				auto name = "Value"~((i > 0) ? "" : to!string(i++));
				s = " property "~t.stringof~" "~name~"();\n";
				s ~=" property "~t.stringof~" "~name~"("~t.stringof~" 
value);\n";
			}
			return s;
		}
		enum _ = eval();
		pragma(msg, _);
	}

	mixin("mixin(_!T);");
	
}

interface a(MT...)
{
	mixin PropertyBuilder!MT;
}
Jul 08 2013
next sibling parent reply "JS" <js.mdnq gmail.com> writes:
On Monday, 8 July 2013 at 11:56:40 UTC, JS wrote:
 The following code inserts properties for each type,

 auto name = "Value"~((i == 0) ? "" : to!string(i++));

 always as the i == 0 evaluate to true.

 1. obviously ints work because the code below works with i as a 
 counter but we can't do a simple compare on it... this seems 
 like a bug.

this is a mistake, I'm not sure what's going on, i seems to increment but name always seems to evaluate to the largest i.
Jul 08 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/09/13 00:57, JS wrote:
 On Monday, 8 July 2013 at 12:11:36 UTC, Dicebot wrote:
 On Monday, 8 July 2013 at 12:08:44 UTC, JS wrote:
 the issue with the foreach is still under question though, when I try to use a
for loop with i and access TT[i] I get an error about i not being compile time
readable. (maybe this is because of how the type tuple is defined? possibly
need a index method to get the value?)

Because i is not a compile-time value, it is a normal variable. And TT is a type tuple, pure compile-time entity. You really need to study the documentation on this topic or frustration will continue.

This has nothing to do with it... string name = "Value"~((i==0) ? "" : (to!string(i))); i++; works, but string name = "Value"~((i==0) ? "" : (to!string(i++))); but doesn't.... It is a matter of placement of the increment operation on i that is breaking the code and has nothing to do with your default answer of "you don't know how CTFE's work, read the docs!" and "... it's not a compile-time variable".

What should the following program print? void main() { import std.stdio; auto a = 0; a==0 ? writeln("Hello") : writeln("world!"); } artur
Jul 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 8 July 2013 at 11:56:40 UTC, JS wrote:
 ...

CTFE has nothing to do with it. void main() { import std.stdio; int i = 0; writeln(i == 0 ? i : i++); writeln(i); } "i++" is evaluated lazy here. I don't know if it is a bug or matches the spec.
Jul 08 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Monday, 8 July 2013 at 12:03:52 UTC, JS wrote:
 On Monday, 8 July 2013 at 11:56:40 UTC, JS wrote:
 The following code inserts properties for each type,

 auto name = "Value"~((i == 0) ? "" : to!string(i++));

 always as the i == 0 evaluate to true.

 1. obviously ints work because the code below works with i as 
 a counter but we can't do a simple compare on it... this seems 
 like a bug.

this is a mistake, I'm not sure what's going on, i seems to increment but name always seems to evaluate to the largest i.

sheit... sorry, stupid mistake.. the issue with the foreach is still under question though, when I try to use a for loop with i and access TT[i] I get an error about i not being compile time readable. (maybe this is because of how the type tuple is defined? possibly need a index method to get the value?)
Jul 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
P.S. you speak about (i == 0) but your snippet has (i > 0)
Jul 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 8 July 2013 at 12:08:44 UTC, JS wrote:
 the issue with the foreach is still under question though, when 
 I try to use a for loop with i and access TT[i] I get an error 
 about i not being compile time readable. (maybe this is because 
 of how the type tuple is defined? possibly need a index method 
 to get the value?)

Because i is not a compile-time value, it is a normal variable. And TT is a type tuple, pure compile-time entity. You really need to study the documentation on this topic or frustration will continue.
Jul 08 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Monday, 8 July 2013 at 12:09:55 UTC, Dicebot wrote:
 P.S. you speak about (i == 0) but your snippet has (i > 0)

Thats simply because I forgot to change it.. I tried various things... it's not relevant... the problem is back... when I remove the compare on i name is updated, when I don' t it isn't: string name = "Value"~((i == 0) ? "" : to!string(i++)); } produces property int Value(); property int Value(int value); property double Value(); property double Value(double value); property long Value(); property long Value(long value); but string name = "Value"~(to!string(i++)); property int Value0(); property int Value0(int value); property double Value1(); property double Value1(double value); property long Value2(); property long Value2(long value); so the original statement was correct about i==0.
Jul 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
Hello there. Have you read my answer? The very first one?

1) i will never be incremented there and CTFE has nothing to do 
with it.
2) This topic should have been in D.learn
3) If you won't tone down your arrogance, soon there will be no 
one left willing to answer you.
Jul 08 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 8 July 2013 at 11:56:40 UTC, JS wrote:
 The following code inserts properties for each type,

 auto name = "Value"~((i == 0) ? "" : to!string(i++));

 always as the i == 0 evaluate to true.


 My question is, why the heck is it so hard to use basic 
 programming structs inside CTFE's? I know that CTFE's have to 
 work at run time also, so there is a limitation, but:

 1. obviously ints work because the code below works with i as a 
 counter but we can't do a simple compare on it... this seems 
 like a bug.

 2. foreach can be used but a simple for loop can't... makes no 
 sense.

 I know what the average response is going to be but hopefully 
 someone will surprise me with some useful.



 mixin template PropertyBuilder(T...)
 {
 	template _(TT...)
 	{
 		static string eval()
 		{
 			string s;
 			pragma(msg, TT);
 			int i = 0;
 			foreach(t; TT)
 			{
 				auto name = "Value"~((i > 0) ? "" : to!string(i++));
 				s = " property "~t.stringof~" "~name~"();\n";
 				s ~=" property "~t.stringof~" "~name~"("~t.stringof~" 
 value);\n";
 			}
 			return s;
 		}
 		enum _ = eval();
 		pragma(msg, _);
 	}

 	mixin("mixin(_!T);");
 	
 }

 interface a(MT...)
 {
 	mixin PropertyBuilder!MT;
 }

after weeding out the bugs and unusual things, plus letting foreach manage i: mixin template PropertyBuilder(T...) { template _(TT...) { static string eval() { string s; foreach(i, t; TT) { auto name = "Value"~((i > 0) ? to!string(i) : ""); s ~= " property "~t.stringof~" "~name~"();\n"; s ~=" property void "~name~"("~t.stringof~" value);\n"; } return s; } enum _ = eval(); } mixin("mixin(_!T);"); } which works fine. The i++ in to!string not having any effect is rather surprising, I agree.
Jul 08 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 8 July 2013 at 12:08:39 UTC, Dicebot wrote:
 On Monday, 8 July 2013 at 11:56:40 UTC, JS wrote:
 ...

CTFE has nothing to do with it. void main() { import std.stdio; int i = 0; writeln(i == 0 ? i : i++); writeln(i); } "i++" is evaluated lazy here. I don't know if it is a bug or matches the spec.

Nothing wrong with that. It's the normal behaviour in C, and it makes perfect sense if you just expand the ternary out to if/else.
Jul 08 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 8 July 2013 at 12:41:22 UTC, John Colvin wrote:
 The i++ in to!string not having any effect is rather 
 surprising, I agree.

Scratch that, there's nothing surprising about it at all. i == 0 on the first iteration and therefore the first branch of the ternary isn't executed. The same thing happens the next iteration and so on, leaving i==0 for every iteration.
Jul 08 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Monday, 8 July 2013 at 12:11:36 UTC, Dicebot wrote:
 On Monday, 8 July 2013 at 12:08:44 UTC, JS wrote:
 the issue with the foreach is still under question though, 
 when I try to use a for loop with i and access TT[i] I get an 
 error about i not being compile time readable. (maybe this is 
 because of how the type tuple is defined? possibly need a 
 index method to get the value?)

Because i is not a compile-time value, it is a normal variable. And TT is a type tuple, pure compile-time entity. You really need to study the documentation on this topic or frustration will continue.

This has nothing to do with it... string name = "Value"~((i==0) ? "" : (to!string(i))); i++; works, but string name = "Value"~((i==0) ? "" : (to!string(i++))); but doesn't.... It is a matter of placement of the increment operation on i that is breaking the code and has nothing to do with your default answer of "you don't know how CTFE's work, read the docs!" and "... it's not a compile-time variable". If i's not possible to use at compile time then none of the following code examples should work One could argue that depending on how to!string works could be the issue, but this has nothing to do with i, which is what you have stated, but to!string. If it is to!string or templates in general that are the issue then it is confusing to have the same syntax for compile time and runtime but some common runtime syntax doesn't work. e.g., int x = 0; writeln(x); to!string(x++); writeln(x); works fine at run-time, but to!string(i++) fails and to!string(i); i++; works in CTFE... So, either this is what you were getting at but didn't explain it well(making the issue about i when it is about CTFE templates) or you didn't understand the issue yourself. int i = 0; foreach(t; T) { string name = "Value"~((i==0) ? "" : (to!string(i))); i++; } vs int i = 0; foreach(t; T) { string name = "Value"~((i==0) ? "" : (to!string(i++))); } vs foreach(i, t; T) { string name = "Value"~((i==0) ? "" : (to!string(i))); } all are suppose to do the same thing and are all essentially semantically identical... they should do the same. (at least according to your logic and the compiler error message that says the issue is with i)
Jul 08 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
Ultimately, the point is, that I thought CTFE's were suppose to 
be compile time runnable functions. The problem is, the actual 
language grammar changes. can use i++ as an argument to a 
template at runtime without issue but not at compile time... and 
since this seems to be the case from the examples I've posted, 
this causes, at least for me, a lot of confusion. (who knows what 
other differences there are) (and IMO they are flaws in the CTFE 
system... although maybe there is some deep underlying reason why 
it must be done that way)
Jul 08 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 8 July 2013 at 22:57:17 UTC, JS wrote:
 	int i = 0;
 	foreach(t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i)));
 		i++;
 	}

That increments i, both ctfe and rt.
 vs

 	int i = 0;
 	foreach(t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i++)));		
 	}

This will never increment i, whether in ctfe or at runtime. The entire "(to!string(i++))" will never be executed.
 vs


 	foreach(i, t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i)));
 	}

This will increment i, both in ctfe and at runtime.
Jul 08 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Monday, 8 July 2013 at 23:36:46 UTC, John Colvin wrote:
 On Monday, 8 July 2013 at 22:57:17 UTC, JS wrote:
 	int i = 0;
 	foreach(t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i)));
 		i++;
 	}

That increments i, both ctfe and rt.
 vs

 	int i = 0;
 	foreach(t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i++)));		
 	}

This will never increment i, whether in ctfe or at runtime. The entire "(to!string(i++))" will never be executed.

oh shit! lol... fuck I'm stupid! ;/
 vs


 	foreach(i, t; T)
 	{
 		string name = "Value"~((i==0) ? "" : (to!string(i)));
 	}

This will increment i, both in ctfe and at runtime.

Jul 08 2013
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 09 Jul 2013 01:02:12 +0200
schrieb "JS" <js.mdnq gmail.com>:

 Ultimately, the point is, that I thought CTFE's were suppose to 
 be compile time runnable functions. The problem is, the actual 
 language grammar changes. can use i++ as an argument to a 
 template at runtime without issue but not at compile time... and 
 since this seems to be the case from the examples I've posted, 
 this causes, at least for me, a lot of confusion. (who knows what 
 other differences there are) (and IMO they are flaws in the CTFE 
 system... although maybe there is some deep underlying reason why 
 it must be done that way)

If you look through the thread, others said that the behavoir is the same in C at runtime. Your use of the ternary operator is the problem. Only the branch that is taken is executed. This should be obvious, but I agree that when the other branch contains an i++ it looks like it should be executed. Please look at the ternary operator as an if and else and it will become clear why your increment works when you put it on a separate line. TL;DR: It has nothing to do with flaws in D or CTFE. At least not this time around. ;) -- Marco
Jul 08 2013