digitalmars.D.learn - Template question
- Chad J (18/18) Oct 04 2006 I'm trying to write a template that, when instantiated, gives a value
- Sean Kelly (4/6) Oct 04 2006 I don't think this is possible. Once a template is evaluated that's it....
- Chad J (3/14) Oct 04 2006 Oh, bummer. Is there another way to do what I want to do at
- Thomas Kuehne (26/40) Oct 04 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Chad J (4/56) Oct 04 2006 Maybe I'm wrong, but it seems like it can't guarantee uniqueness due to
- BCS (13/31) Oct 04 2006 It would require a new feature but...
- Reiner Pope (34/37) Oct 04 2006 The reason this sort of thing is not supported with templates is that it...
- Chad J (8/57) Oct 04 2006 I see. I was kind of expecting arbitrary order of evaluation, but
- Don Clugston (8/66) Oct 05 2006 A tutorial would be nice. I started writing one a while ago, but then
- Derek Parnell (73/75) Oct 04 2006 This does not answer your question, but I was wondering why you need thi...
- Markus Dangl (18/41) Oct 05 2006 This is a bit complicated to explain: Compile time constructs
- rm (5/51) Oct 06 2006 could you elaborate with an example I can compile,
- Markus Dangl (43/51) Oct 06 2006 Here is a full example, it compiles and runs with my DMD 0.168:
- rm (5/63) Oct 06 2006 thx for the itoa stuff, was searching for that!
- Markus Dangl (5/12) Oct 07 2006 I actually took itoa from Tom S' ctrace:
- Don Clugston (2/16) Oct 08 2006
I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work: import std.stdio; template GetUID() { const ulong accumulator; static if ( ++accumulator != 0 ) const ulong GetUID = accumulator; else static assert(0); } void main() { writefln( GetUID!() ); // should print 1 writefln( GetUID!() ); // should print 2 } Hopefully that gives a good idea of what I am shooting for.
Oct 04 2006
Chad J > wrote:I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.I don't think this is possible. Once a template is evaluated that's it. Future references to a template do not cause a re-evaluation. Sean
Oct 04 2006
Sean Kelly wrote:Chad J > wrote:Oh, bummer. Is there another way to do what I want to do at compile-time, besides just manually writing the numbers in?I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.I don't think this is possible. Once a template is evaluated that's it. Future references to a template do not cause a re-evaluation. Sean
Oct 04 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Chad J schrieb am 2006-10-04:Sean Kelly wrote:Here is a kludge(limitation: only UID instantiation per line and file allowed): Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFJF8MLK5blCcjpWoRArtDAJ42K2nEhKcEWNvpp3q+LjHVdBzAfwCfa8dT rS6sQyT7s1XUic1TLz3Y2+A= =+5nW -----END PGP SIGNATURE-----Chad J > wrote:Oh, bummer. Is there another way to do what I want to do at compile-time, besides just manually writing the numbers in?I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.I don't think this is possible. Once a template is evaluated that's it. Future references to a template do not cause a re-evaluation. Sean
Oct 04 2006
Thomas Kuehne wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Chad J schrieb am 2006-10-04:Maybe I'm wrong, but it seems like it can't guarantee uniqueness due to hashing of the files. Anyhow, it's a useful template to keep in mind. Thanks for that!Sean Kelly wrote:Here is a kludge(limitation: only UID instantiation per line and file allowed): Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFJF8MLK5blCcjpWoRArtDAJ42K2nEhKcEWNvpp3q+LjHVdBzAfwCfa8dT rS6sQyT7s1XUic1TLz3Y2+A= =+5nW -----END PGP SIGNATURE-----Chad J > wrote:Oh, bummer. Is there another way to do what I want to do at compile-time, besides just manually writing the numbers in?I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.I don't think this is possible. Once a template is evaluated that's it. Future references to a template do not cause a re-evaluation. Sean
Oct 04 2006
Chad J > wrote:Sean Kelly wrote:It would require a new feature but... <code> enum Root{} enum foo : Root{a} // a is distinct from all values in types deriving from Root foo.a; enum bar : Root{a} // a is distinct from all values in types deriving from Root bar.a </code> Implementing this would be a pain though (putting the enums in different files...) :PChad J > wrote:Oh, bummer. Is there another way to do what I want to do at compile-time, besides just manually writing the numbers in?I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.I don't think this is possible. Once a template is evaluated that's it. Future references to a template do not cause a re-evaluation. Sean
Oct 04 2006
Chad J > wrote:I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work:The reason this sort of thing is not supported with templates is that it creates ambiguities. Template evaluation is lazy, meaning (a) it is only done when it is required, and (b) it can be done in any order. This is really the obvious way to do it. For example, consider the following code: void foo() { writefln( GetUID!() ); } void bar() { writefln( GetUID!() ); } void main() { bar(); foo(); } Which one prints 1, and which one prints 2? I can think of two arbitrary rules which resolve the ambiguity: 1. evaluate all templates from the top of the source code down; or 2. evaluate all templates according to execution order. The problem is that 1. is arbitrary and contradicts the assumption and aim the rearranging the order of functions won't change anything, and 2. is not always decidable, vis a vis the halting problem. I don't actually have an idea of what you are trying to accomplish, though. If just simple accumulator, then write it as actual D code and let the optimizer inline and pre-evaluate it without your assistance. If you want something else, I'm sure there is a way to do it within the template system -- you'll probably find Thomas and BCS's suggestions the right sort of thing. Cheers, Reiner
Oct 04 2006
Reiner Pope wrote:Chad J > wrote:I see. I was kind of expecting arbitrary order of evaluation, but didn't care really. This one was mostly just a learning excercise for me to get a better feel for templates. In a way it would be nice if there was some sort of tutorial type resource for D templates; hopefully something that doesn't rely on C++ background. For a long time I just ignored them because they were scary :) Anyhow, thanks for the info!I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work:The reason this sort of thing is not supported with templates is that it creates ambiguities. Template evaluation is lazy, meaning (a) it is only done when it is required, and (b) it can be done in any order. This is really the obvious way to do it. For example, consider the following code: void foo() { writefln( GetUID!() ); } void bar() { writefln( GetUID!() ); } void main() { bar(); foo(); } Which one prints 1, and which one prints 2? I can think of two arbitrary rules which resolve the ambiguity: 1. evaluate all templates from the top of the source code down; or 2. evaluate all templates according to execution order. The problem is that 1. is arbitrary and contradicts the assumption and aim the rearranging the order of functions won't change anything, and 2. is not always decidable, vis a vis the halting problem. I don't actually have an idea of what you are trying to accomplish, though. If just simple accumulator, then write it as actual D code and let the optimizer inline and pre-evaluate it without your assistance. If you want something else, I'm sure there is a way to do it within the template system -- you'll probably find Thomas and BCS's suggestions the right sort of thing. Cheers, Reiner
Oct 04 2006
Chad J > wrote:Reiner Pope wrote:A tutorial would be nice. I started writing one a while ago, but then the language changed so much, it became completely obsolete! And as recently as DMD 0.166, Oskar's patches for member templates have changed the rules again. Although some 'best practices' are now well understood, some 'how-tos' are still unknown by everyone. Nobody has more than 35 days experience with the current D templates. Not even Walter. <g>Chad J > wrote:I see. I was kind of expecting arbitrary order of evaluation, but didn't care really. This one was mostly just a learning excercise for me to get a better feel for templates. In a way it would be nice if there was some sort of tutorial type resource for D templates; hopefully something that doesn't rely on C++ background. For a long time I just ignored them because they were scary :)I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work:The reason this sort of thing is not supported with templates is that it creates ambiguities. Template evaluation is lazy, meaning (a) it is only done when it is required, and (b) it can be done in any order. This is really the obvious way to do it. For example, consider the following code: void foo() { writefln( GetUID!() ); } void bar() { writefln( GetUID!() ); } void main() { bar(); foo(); } Which one prints 1, and which one prints 2? I can think of two arbitrary rules which resolve the ambiguity: 1. evaluate all templates from the top of the source code down; or 2. evaluate all templates according to execution order. The problem is that 1. is arbitrary and contradicts the assumption and aim the rearranging the order of functions won't change anything, and 2. is not always decidable, vis a vis the halting problem. I don't actually have an idea of what you are trying to accomplish, though. If just simple accumulator, then write it as actual D code and let the optimizer inline and pre-evaluate it without your assistance. If you want something else, I'm sure there is a way to do it within the template system -- you'll probably find Thomas and BCS's suggestions the right sort of thing. Cheers, Reiner
Oct 05 2006
On Wed, 04 Oct 2006 15:52:01 -0400, Chad J wrote:I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one.This does not answer your question, but I was wondering why you need this functionality at compile time. I do something similar but it happens at application initialization time and is simple to code. import util.series; import std.stdio; Series UID; // Declare the series. static this() { UID.Next = 1; // Set first value to one. } void main() { writefln( UID.Next ); // should print 1 writefln( UID.Next ); // should print 2 } Where series.d is // ------------------ module util.series; struct Series { private { ulong mValue; ulong mIncr; } ulong Next() { ulong lCV; lCV = mValue; mValue += (mIncr+1); return lCV; } void Next(ulong pInit) { mValue = pInit; } ulong Current() { return mValue; } ulong Prev() { return mValue - (mIncr+1); } void Increment(ulong pInit = 1) { mIncr = pInit-1; } } unittest { Series a; assert( a.Next == 0); assert( a.Next == 1); assert( a.Next == 2); assert( a.Current == 3); a.Increment = 2; assert( a.Next == 3); assert( a.Next == 5); assert( a.Prev == 5); a.Next = 100; assert( a.Current == 100); assert( a.Next == 100); assert( a.Next == 102); } // ------[ end of file ]----------------- -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 5/10/2006 2:15:46 PM
Oct 04 2006
Chad J > schrieb:I'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work: import std.stdio; template GetUID() { const ulong accumulator; static if ( ++accumulator != 0 ) const ulong GetUID = accumulator; else static assert(0); } void main() { writefln( GetUID!() ); // should print 1 writefln( GetUID!() ); // should print 2 } Hopefully that gives a good idea of what I am shooting for.This is a bit complicated to explain: Compile time constructs (templates) work just like a functional language: They are fully deterministic, the only way you can modify the result is by modifying the parameters. If you want to use a counter you'd have to use a recursive approach like this: template counter(uint max, uint i=0) { void initialize() { writefln(i); // Insert your statement hier static if (i<max) counter!(max, i+1).initialize(); } } Although that's perhaps not a real speedup compared to initializing the program with a counter at runtime...
Oct 05 2006
Markus Dangl wrote:Chad J > schrieb:could you elaborate with an example I can compile, at the moment I don't see how to put it in a working app thx, roelI'm trying to write a template that, when instantiated, gives a value that is the same as the last time it was instantiated plus one. Here is some code I tried, but it doesn't work: import std.stdio; template GetUID() { const ulong accumulator; static if ( ++accumulator != 0 ) const ulong GetUID = accumulator; else static assert(0); } void main() { writefln( GetUID!() ); // should print 1 writefln( GetUID!() ); // should print 2 } Hopefully that gives a good idea of what I am shooting for.This is a bit complicated to explain: Compile time constructs (templates) work just like a functional language: They are fully deterministic, the only way you can modify the result is by modifying the parameters. If you want to use a counter you'd have to use a recursive approach like this: template counter(uint max, uint i=0) { void initialize() { writefln(i); // Insert your statement hier static if (i<max) counter!(max, i+1).initialize(); } } Although that's perhaps not a real speedup compared to initializing the program with a counter at runtime...
Oct 06 2006
Here is a full example, it compiles and runs with my DMD 0.168: ===== module CompileTimeCounter; import std.stdio; pragma(msg, "-- This is at compile time"); // Converts an integer i to a string at compile time. // Needed for pragma(msg). template itoa(int i) { static if (i < 10) const char[] itoa = "0123456789"[i..i+1]; else const char[] itoa = itoa!(i/10) ~ "0123456789"[i%10]; } // A counter that runs at compile time. template counter(uint max, uint i=0) { void initialize() { pragma(msg, itoa!(i)); writefln(i); static if (i<max) counter!(max, i+1).initialize(); } } // ncounter has to be const, so it is accessible at compile time. const int ncounter = 10; int main(char[][]args) { writefln("-- This is at run time"); counter!(ncounter).initialize(); return 0; } ==== As you can see when you're compiling it counts from 0 to 10 (including 10). When you run the resulting exe file, it will also print the numbers from 0 to 10, but this time there isn't a real counter involved, it's just like having writefln(0); writefln(1); writefln(2); ... in your code. To be exact, each writefln() is wrapped up in a seperate function, this is why i think that a counter at compile time isn't really efficient.Although that's perhaps not a real speedup compared to initializing the program with a counter at runtime...could you elaborate with an example I can compile, at the moment I don't see how to put it in a working app thx, roel
Oct 06 2006
Markus Dangl wrote:thx for the itoa stuff, was searching for that! my problem was indeed that I couldn't come up with a identical reusable statement. roelHere is a full example, it compiles and runs with my DMD 0.168: ===== module CompileTimeCounter; import std.stdio; pragma(msg, "-- This is at compile time"); // Converts an integer i to a string at compile time. // Needed for pragma(msg). template itoa(int i) { static if (i < 10) const char[] itoa = "0123456789"[i..i+1]; else const char[] itoa = itoa!(i/10) ~ "0123456789"[i%10]; } // A counter that runs at compile time. template counter(uint max, uint i=0) { void initialize() { pragma(msg, itoa!(i)); writefln(i); static if (i<max) counter!(max, i+1).initialize(); } } // ncounter has to be const, so it is accessible at compile time. const int ncounter = 10; int main(char[][]args) { writefln("-- This is at run time"); counter!(ncounter).initialize(); return 0; } ==== As you can see when you're compiling it counts from 0 to 10 (including 10). When you run the resulting exe file, it will also print the numbers from 0 to 10, but this time there isn't a real counter involved, it's just like having writefln(0); writefln(1); writefln(2); ... in your code. To be exact, each writefln() is wrapped up in a seperate function, this is why i think that a counter at compile time isn't really efficient.Although that's perhaps not a real speedup compared to initializing the program with a counter at runtime...could you elaborate with an example I can compile, at the moment I don't see how to put it in a working app thx, roel
Oct 06 2006
rm schrieb:thx for the itoa stuff, was searching for that! my problem was indeed that I couldn't come up with a identical reusable statement. roelI actually took itoa from Tom S' ctrace: http://www-users.mat.uni.torun.pl/~h3r3tic/ctrace/ I have some compile time lists that i designed myself, and some other stuff, if you ever need lists at compile time contact me by mail :)
Oct 07 2006
Markus Dangl wrote:rm schrieb:And he took it from mine... this stuff goes back a long way.thx for the itoa stuff, was searching for that! my problem was indeed that I couldn't come up with a identical reusable statement. roelI actually took itoa from Tom S' ctrace: http://www-users.mat.uni.torun.pl/~h3r3tic/ctrace/I have some compile time lists that i designed myself, and some other stuff, if you ever need lists at compile time contact me by mail :)
Oct 08 2006