Template recursion and compile-time evaluation.
Reiner Pope
reiner.pope at REMOVE.THIS.gmail.com
Sun Aug 13 00:39:51 PDT 2006
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
More information about the Digitalmars-d
mailing list