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)
commonPrefix
Die Verwendung von Introspektion zur Kompilierzeit ist
in Phobos allgegenwärtig. Z.B. differenziert commonPrefix
zwischen RandomAccessRange
s 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__);'