digitalmars.D - Template recursion and compile-time evaluation.
- Reiner Pope (64/64) Aug 13 2006 What are the rules about template recursion, and compile time evaluation...
- Walter Bright (7/26) Aug 14 2006 This happens when the compiler itself runs out of stack space. This
What are the rules about template recursion, and compile time evaluation in general? For example, the following code produces an error on my computer: import std.stdio; template count(uint n) { static if (n == 0) const uint count = 0; else const uint count = 1 + count!(n-1); } int main(char[][] args) { writefln("%d", count!(3008)); return 0; } factorial.d(6): template instance factorial.count!(1u) recursive expansion So it recurses too deeply. But if I sidestep the recursion, then it's OK. A double-instantiation works: int main(char[][] args) { writefln("%d", count!(3002)); // Doesn't recurse as deep writefln("%d", count!(3008)); // Can stop recursing when 3002 is reached return 0; } But when I use the same process to get much bigger, I get problems again: int main(char[][] args) { writefln("%d", count!(3007)); writefln("%d", count!(4000)); writefln("%d", count!(5000)); return 0; } When attempting to compile, this gives me: c:\reiner\d\tools\dmd\bin\..\..\dm\bin\link.exe factorial,,,user32+kernel32/noi; --- errorlevel 1 as well as a messagebox entitled 'Unexpected OPTLINK Termination at EIP=0044C37B' with a dump of the registers. And the compiler is crashed by user code. Not a good thing, in my opinion. What is the deal with compile-time recursion? Is doing heavy stuff with it supposed to be avoided? If so, why is that sort of thing discussed in the spec (the factorial example on the templates page)? What template recursion depth must a compiler guarantee? If there are no guarantees, then what does one do about the fact that code may compile on one computer but not another? However, trying this out on runtime code, the recursion limit is much higher (on my computer, it easily reaches 50000), and it executes much faster. However, the real point is that it produces a *catchable* error: uint countDynamic(uint n) { if (n == 0) return 0; return 1 + countDynamic(n-1); } int main(char[][] args) { writefln("%d", countDynamic(100000)); // This throws a Stack Overflow which can be caught with try/catch return 0; } Since there is such a big difference in speed between runtime evaluation and template-based evaluation of effectively the same code, then perhaps using templates for compile-time evaluation is the wrong approach? Cheers, Reiner
Aug 13 2006
Reiner Pope wrote:What are the rules about template recursion, and compile time evaluation in general? For example, the following code produces an error on my computer: import std.stdio; template count(uint n) { static if (n == 0) const uint count = 0; else const uint count = 1 + count!(n-1); } int main(char[][] args) { writefln("%d", count!(3008)); return 0; } factorial.d(6): template instance factorial.count!(1u) recursive expansionThis happens when the compiler itself runs out of stack space. This amount will vary from machine to machine, operating system to operating system. While the compiler is expected to do its best to accommodate recursion as much as possible, I recommend that for practical reasons one should think of a different algorithm if recursion levels more than 100 are used.
Aug 14 2006