www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - more enum and pragma troubles

reply captaindet <2krnk gmx.net> writes:
are these bugs or expected behavior? (2 issues, see code below)

i thought enums are just compile time copy&paste magic so i cannot think of a
reason why it should not be available at compile time...

if buggy, what is broken, enum (really bad) or pragma(msg,...) (worse enough)?
and are they in bugzilla already? (looked but nothing caught my eye)

if expected behavior, can someone pls explain.

cheers /det


import std.stdio;

enum Test{
	test2 = 2,
	test4 = 4
}

enum foo = Test.test2;
Test bar = Test.test4;

pragma( msg, foo );		// why does it print: cast(Test)2
				// it should be: test2
				// or at least simply: 2

//  pragma( msg, bar );		// Error: variable bar cannot be read at compile time

void main(){
	writeln( typeof(foo).stringof, " = ", foo );	
		// prints as expected: Test = test2
	writeln( typeof(bar).stringof, " = ", bar );	
		// prints as expected: Test = test4
}
Aug 16 2013
next sibling parent reply "JS" <js.mdnq gmail.com> writes:
On Saturday, 17 August 2013 at 05:22:53 UTC, captaindet wrote:
 are these bugs or expected behavior? (2 issues, see code below)

 i thought enums are just compile time copy&paste magic so i 
 cannot think of a reason why it should not be available at 
 compile time...

 if buggy, what is broken, enum (really bad) or pragma(msg,...) 
 (worse enough)?
 and are they in bugzilla already? (looked but nothing caught my 
 eye)

 if expected behavior, can someone pls explain.

 cheers /det


 import std.stdio;

 enum Test{
 	test2 = 2,
 	test4 = 4
 }

 enum foo = Test.test2;
 Test bar = Test.test4;

 pragma( msg, foo );		// why does it print: cast(Test)2
 				// it should be: test2
 				// or at least simply: 2
It is 2! Notice the 2 at the end? The cast is just mumbo jumbo due to the the compiler deals with the stuff. You can remove the casts manually if you don't like them.
 //  pragma( msg, bar );		// Error: variable bar cannot be read 
 at compile time
Because bar is not a compile time constant. It is an runtime object. pragma can't display certain things that it doesn't know about due to the way the compiler works. It's unfortunate in some cases that it simply doesn't work correctly, in others, such as this, it works as expected. You could argue that the compiler should know that bar is known at compile time up to the pragma, and I would agree... but the compiler simply isn't that smart.
 void main(){
 	writeln( typeof(foo).stringof, " = ", foo );	
 		// prints as expected: Test = test2
 	writeln( typeof(bar).stringof, " = ", bar );	
 		// prints as expected: Test = test4
 }
these print the value at runtime. In this case the compiler is already out of the picture. Basically pragmas are evaluated during compile time, if the compiler can't figure out the value(or is too stupid) then it can't print them and throws an error. In fact, even in CTFE stuff pragma doesn't function like one would hope. This again, is due to the way the compiler works. Just a quirky and unfortunate way that the d compiler works.
Aug 16 2013
parent reply captaindet <2krnk gmx.net> writes:
[enum foo = Test.test2;]

On 2013-08-17 01:03, JS wrote:
 pragma( msg, foo ); // why does it print: cast(Test)2
 // it should be: test2
 // or at least simply: 2
It is 2! Notice the 2 at the end? The cast is just mumbo jumbo due to the the compiler deals with the stuff. You can remove the casts manually if you don't like them.
i saw the 2, but foo semantically contains a Test Test.test2 (this is the idea) or technically an int 2. don't understand why pragma displays an explicit cast here. maybe some internals that are leaking through the pragma(msg,...) implementation.
 // pragma( msg, bar ); // Error: variable bar cannot be read at compile time
Because bar is not a compile time constant. It is an runtime object. pragma can't display certain things that it doesn't know about due to the way the compiler works. It's unfortunate in some cases that it simply doesn't work correctly, in others, such as this, it works as expected. You could argue that the compiler should know that bar is known at compile time up to the pragma, and I would agree... but the compiler simply isn't that smart.
but this is my very point! my understanding was that enums are all compile time entities that are just copied around. at compile time. a named enum type should make no difference. where is it documented that named enums become runtime objects? but you are right that this seems to be the case here and that pragma(msg,...) is off the hook this time: enum Test{ test2 = 2, test4 = 4 } enum foo = Test.test2; Test bar = Test.test4; // enum wtf = bar; // Error: variable bar cannot be read at compile time /det
Aug 16 2013
next sibling parent captaindet <2krnk gmx.net> writes:
On 2013-08-17 01:51, captaindet wrote:
 named enums become runtime objects
-> named enums become runtime *only* objects
Aug 16 2013
prev sibling parent captaindet <2krnk gmx.net> writes:
On 2013-08-17 01:51, captaindet wrote:
 my understanding was that enums are all compile time entities that
 are just copied around. at compile time. a named enum type should
 make no difference.
oh i see now, naming them is just creating a disguise for the base type. then they can become compile-time-known when declared const (see below). only anonymous enum (manifest constant) are true compile time objects. reminds me of my (type)tuple confusion. two completely different animals/concepts, with similar/confusing syntax and blurry docs. module demo; import std.stdio; enum Test{ test2 = 2, test4 = 4 } enum foo = Test.test2; const Test bar = Test.test4; // does the trick enum wtf = bar; pragma( msg, foo ); // prints: cast(Test)2 pragma( msg, bar ); // pritns: cast(Test)4 void main(){ writeln( typeof(foo).stringof, " = ", foo ); // prints: Test = test2 writeln( typeof(bar).stringof, " = ", bar ); // prints: const(Test) = test4 }
Aug 17 2013
prev sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Saturday, 17 August 2013 at 05:22:53 UTC, captaindet wrote:
 import std.stdio;

 enum Test{
 	test2 = 2,
 	test4 = 4
 }
Enumeration.
 enum foo = Test.test2;
Manifest Const
 Test bar = Test.test4;
Runtime variable. Enum is being abused. In the first case you are declaring an enumeration[1], these values are known at compile time. Second you defined a manifest constant, this is what you would see from #define in C. The symbol, foo, is replaced by the right hand side when referenced. Third you've declared a variable, bar, which will store your enumerated value, 4. Variables are not compile time, even if the value stored came from a compile time known value. int foobar = 5; // 5 is known at compile time, foobar is not.
 pragma( msg, foo );		// why does it print: cast(Test)2
You are referring to a manifest constant, this is a simple textual replacement. Enumerations are typed, 2 is not a Test, so the compiler will write out a cast so the type system is happy. Similarly Test.test2 is not the value of foo, foo is a signal to the compiler to insert "cast(Test)2." Hope that makes sense. 1. http://en.wikipedia.org/wiki/Enumeration
Aug 17 2013
parent reply captaindet <2krnk gmx.net> writes:
On 2013-08-17 14:36, Jesse Phillips wrote:
 Third you've declared a variable, bar, which will store your
 enumerated value, 4. Variables are not compile time, even if the
 value stored came from a compile time known value.
yep, it completely escaped me that these are 'normal' variables. and i have realized now that i can make them known at compile time the same way as is done for other 'normal' variables, by declaring them const ;)
 pragma( msg, foo ); // why does it print: cast(Test)2
You are referring to a manifest constant, this is a simple textual replacement. Enumerations are typed, 2 is not a Test, so the compiler will write out a cast so the type system is happy. Similarly Test.test2 is not the value of foo, foo is a signal to the compiler to insert "cast(Test)2." Hope that makes sense.
things are becoming clearer now. thanks for your explanation, jesse! /det
Aug 17 2013
parent reply "JS" <js.mdnq gmail.com> writes:
On Sunday, 18 August 2013 at 00:17:22 UTC, captaindet wrote:
 On 2013-08-17 14:36, Jesse Phillips wrote:
 Third you've declared a variable, bar, which will store your
 enumerated value, 4. Variables are not compile time, even if 
 the
 value stored came from a compile time known value.
yep, it completely escaped me that these are 'normal' variables. and i have realized now that i can make them known at compile time the same way as is done for other 'normal' variables, by declaring them const ;)
But if they are const then what good does that do you? Just use an alias or enum in the first place?
Aug 17 2013
parent reply captaindet <2krnk gmx.net> writes:
On 2013-08-17 21:54, JS wrote:
 On Sunday, 18 August 2013 at 00:17:22 UTC, captaindet wrote:
 On 2013-08-17 14:36, Jesse Phillips wrote:
 Third you've declared a variable, bar, which will store your
 enumerated value, 4. Variables are not compile time, even if the
 value stored came from a compile time known value.
yep, it completely escaped me that these are 'normal' variables. and i have realized now that i can make them known at compile time the same way as is done for other 'normal' variables, by declaring them const ;)
But if they are const then what good does that do you? Just use an alias or enum in the first place?
to be honest, i have not found a use case ;) highest priority was that i understood what was going on here... how did i get there? i was looking for an easy way to get pragma(msg,...) to print the given name for an enumerated value. in this example test2 or test4 instead of 2 and 4 - just like write is doing it at runtime. so i was playing around with the different variants of enum to see if i could get it working somehow.. and got sidetracked.... in the end i stuck to manifest constant enums storing the enumerated values and found that pragma( msg, to!string(foo) ); is doing the trick. /det
Aug 18 2013
parent reply "JS" <js.mdnq gmail.com> writes:
On Monday, 19 August 2013 at 04:37:58 UTC, captaindet wrote:
 On 2013-08-17 21:54, JS wrote:
 On Sunday, 18 August 2013 at 00:17:22 UTC, captaindet wrote:
 On 2013-08-17 14:36, Jesse Phillips wrote:
 Third you've declared a variable, bar, which will store your
 enumerated value, 4. Variables are not compile time, even if 
 the
 value stored came from a compile time known value.
yep, it completely escaped me that these are 'normal' variables. and i have realized now that i can make them known at compile time the same way as is done for other 'normal' variables, by declaring them const ;)
But if they are const then what good does that do you? Just use an alias or enum in the first place?
to be honest, i have not found a use case ;) highest priority was that i understood what was going on here... how did i get there? i was looking for an easy way to get pragma(msg,...) to print the given name for an enumerated value. in this example test2 or test4 instead of 2 and 4 - just like write is doing it at runtime. so i was playing around with the different variants of enum to see if i could get it working somehow.. and got sidetracked.... in the end i stuck to manifest constant enums storing the enumerated values and found that pragma( msg, to!string(foo) ); is doing the trick. /det
I had the same issues, it is not an issue with logic but with the weird way dmd works(pragma is handled very early on and before ctfe's are completely parsed). Remember you can use ctfe's to format strings any way you want and even do logic and other stuff but you can't use pragma's inside the ctfe on ctfe variables(because as far as pragma is concerned, they are run time at that point). module main; import std.stdio, std.conv; template foo(alias T) { string foo(string s) { string x = to!string(T) ~ s ~ "yyyy"; //pragma(msg, x); // pragma see's x as a run time variable(or rather pragma is executed before x is truly defined) return x; } } int main(string[] argv) { pragma(msg, foo!("asf")("xxx")); // note, it prints what the commented pragma is suppose to print, but this one works!!! Because it is outside the ctfe and foo!(...) can be computed at compile time readln(); return 0; } I really believe the issue is with the compiler and is a bug. Somehow x gets marked as run time, probably because ctfe's are suppose to work at run time too... even though in this instance it is being used at compile time. (so it should work)
Aug 18 2013
parent captaindet <2krnk gmx.net> writes:
On 2013-08-19 00:31, JS wrote:

 module main;

 import std.stdio, std.conv;

 template foo(alias T)
 {
 string foo(string s)
 {
 string x = to!string(T) ~ s ~ "yyyy";
 //pragma(msg, x); // pragma see's x as a run time variable(or rather pragma is
executed before x is truly defined)
 return x;
 }
well, i think i understand what is going on in your example. here x is a runtime value because 's' is passed as a function argument (always runtime within this very function). template instantiation (this is when pragmas(msg) is already called) comes first and at this time 's' is unknown, as the instantiated function could be later called with whatever 's' - the compiler cannot know what 's' at this point. tricks i found around this: a) if current structure of example program is required (i.s. definition of foo), add a wrapper template for compile time printing: template _dbg_foo(alias T, string s){ enum x = foo!(T)(s); pragma(msg, x); enum _dbg_foo = x; } b) if foo does not need to have 's' as an argument, make it a template parameter, too. you also have to use an enum instead of a string for temporary storage: string foo2(alias T, string s)(){ enum x = to!string(T) ~ s ~ "yyyy"; pragma(msg, x); return x; } the problems i currently face during CTFE are more like: a) in some cases manifest enums are broken in that they don't contain working compile time copy&paste values. this is currently the case for TypeTuples. i think this will be fixed in the next DMD release. b) pragma(msg) has not the same behavior as write() when it comes to formating the output of non-string values, it sometimes needs help, e.g. with a to!string() call.
Aug 19 2013