Eine von D's Stärken ist CTFE (Funktionsauswertung zur Kompilierzeit), die, kombiniert mit Introspektion, das Schreiben hoch optimierter generischer Programme möglich macht.
Traits (dt.: Merkmale / Eigenschaften) erlauben es, explizit
erlaubte Eingangstypen zu spezifizieren.
Z.B. kann splitIntoWords beliebige String-Typen
verarbeiten:
S[] splitIntoWord(S)(S input)
if (isSomeString!S)
Dies gilt auch für Template-Parameter. Z.B. kann
myWrapper sicherstellen, dass das hineingereichte
Symbol eine aufrufbare Funktion ist:
void myWrapper(alias f)
if (isCallable!f)
Als einfaches Beispiel wird die Funktion
commonPrefix
aus std.algorithm.searching analysiert,
die das gemeinsame Präfix zweier Ranges ausgibt:
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)
Dies bedeutet, dass die Funktion nur aufrufbar ist und damit kompiliert, wenn:
r1 speicherbar ist (garantiert durch isForwardRange)
r2 iterierbar ist (garantiert durch isInputRange)
pred mit den Elementtypen von r1 und r2 aufrufbar ist
r1 kein narrow string (char[], string, wchar or wstring)
ist - der Einfachheit halber, sonst müsste eine Dekodierung stattfinden
Viele APIs zielen auf Vielseitigkeit, allerdings soll die Verallgemeinerung nicht mit zusätzlicher Laufzeit erkauft werden. Mit Introspektion und CTFE ist es möglich, eine Funktion zur Kompilierzeit zu spezialisieren, um so die beste Performance für gegebene Eingangstypen zu erreichen.
Ein gängiges Problem ist, dass die Länge eines Streams
oder einer Liste, im Gegensatz zu z.B. einem Array, vor
dem Durchschreiten nicht bekannt ist.
Das folgende Beispiel stellt eine einfache Implementation
der std.range-Methode walkLength dar, die das
Durchschreiten für alle iterierbaren Typen verallgemeinert:
static if (hasMember!(r, "length"))
return r.length; // O(1)
else
return r.walkLength; // O(n)
commonPrefixDie Verwendung von Introspektion zur Kompilierzeit ist
in Phobos allgegenwärtig. Z.B. differenziert commonPrefix
zwischen RandomAccessRanges und linear iterierbaren Ranges,
da es in einer RandomAccessRange möglich ist zwischen
Positionen zu springen und so den Algorithmus zu beschleunigen.
std.traits umfasst die meisten von D's traits.
Zusätzlich bietet D einige spezielle Schlüsselwörter für Debuggingzwecke:
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);
}
Mit D's CLI-Auswertung wird time nicht benötigt - CTFE kann benutzt werden!
rdmd --force --eval='pragma(msg, __TIMESTAMP__);'