One of D's powers is its compile-time function evaluation (CTFE) system. Combined with introspection, generic programs can be written and heavy optimizations can be achieved.
Traits allow to specify explicitly what input is accepted.
For example splitIntoWords can operate on any arbitrary string type:
S[] splitIntoWord(S)(S input)
if (isSomeString!S)
This applies to template parameters as well and myWrapper can ensure that the
passed-in symbol is a callable function:
void myWrapper(alias f)
if (isCallable!f)
As a simple example, commonPrefix
from std.algorithm.searching, which returns the common prefix of two ranges,
will be analyzed:
auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2)
if (isForwardRange!R1
isInputRange!R2 &&
is(typeof(binaryFun!pred(r1.front, r2.front)))) &&
!isNarrowString!R1)
This means that the function is only callable and thus compiles if:
r1 is save-able (guaranteed by isForwardRange)
r2 is iterable (guaranteed by isInputRange)
pred is callable with element types of r1 and r2
r1 isn't a narrow string (char[], string, wchar or wstring) - for simplicity, otherwise decoding might be needed
Many APIs aim to be general-purpose, however they don't want to pay with extra runtime for this generalization. With the power of introspection and CTFE, it is possible to specialize a method on compile-time to achieve the best performance given the input types.
A common problem is that in contrast to arrays you might not know the exact length
of a stream or list before walking through it.
Hence a simple implementation of the std.range method walkLength
which generalizes for any iterable type would be:
static if (hasMember!(r, "length"))
return r.length; // O(1)
else
return r.walkLength; // O(n)
commonPrefixThe use of compile-time introspection is ubiquitous in Phobos. For example
commonPrefix differentiates between RandomAccessRanges
and linear iterable ranges because in RandomAccessRange it's possible to jump
between positions and thus speed-up the algorithm.
std.traits wraps most of
D's traits except for some like
compiles that can't be wrapped as it would lead to an immediate compile error:
__traits(compiles, obvious error - $%42); // false
Additionally for debugging purposes D provides a couple of special keywords:
void test(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__,
string func = __FUNCTION__, string pretty = __PRETTY_FUNCTION__)
{
writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', pretty function: '%s'",
file, line, mod, func, pretty);
}
With D's CLI evaluation one doesn't even need time - CTFE can be used!
rdmd --force --eval='pragma(msg, __TIMESTAMP__);'