Одною з переваг D є її система виконання функцій під час компіляції (CTFE). У поєднанні з самоаналізом можна написати узагальнені програми та досягнути потужних оптимізацій.
Traits дозволяють явно вказати, що може бути подано на вхід.
Наприклад, splitIntoWords
може працювати з будь-яким рядковим типом:
S[] splitIntoWord(S)(S input)
if (isSomeString!S)
Це відноситься також до параметрів шаблону. myWrapper
може гарантувати,
що переданий символ можна викликати як функцію:
void myWrapper(alias f)
if (isCallable!f)
Проаналізуємо простий приклад, commonPrefix
з std.algorithm.searching
, який повертає загальний префікс двох діапазонів:
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)
Виклик такої функції скомпілюється тільки якщо:
r1
можна зберегти (гарантовано isForwardRange
)
r2
підтримує ітерацію (гарантовано isInputRange
)
pred
викликається з типами елементів r1
та r2
r1
не "вузький" рядок (char[]
, string
, wchar
чи wstring
) - для простоти, в іншому випадку, може бути необхідне декодування
Багато API націлені на розширення області застосування, проте вони не хочуть платити швидкодією за таке узагальнення. Із силою самоаналізу та CTFE, можна сфокусуватися на методах часу компіляції для досягнення максимальної продуктивності, враховуючи певні вхідні типи.
Найпоширеніша проблема, що на відміну від масивів, ми повинні знати
точну довжину потоку даних або списку перш, ніж працювати з ним.
Тому ми маємо простий метод walkLength
з std.range
,
який є узагальненим для будь-якого ітерабельного типу:
static if (hasMember!(r, "length"))
return r.length; // O(1)
else
return r.walkLength; // O(n)
commonPrefix
У бібліотеці Phobos
самоаналіз під час компіляції використовується
всюди. Наприклад, сommonPrefix
розрізняє діапазони з випадковим
доступом (RandomAccessRange
) та лінійні ітерабельні діапазони, тому
що у RandomAccessRange
можна "перестрибувати" між позиціями і, таким
чином, прискорювати виконання алгоритму.
std.traits - оболонка навколо
більшості характеристик (traits) D,
за винятком деяких, наприклад compiles
, який неможливо "обернути",
так як це призведе до негайної помилки компіляції:
__traits(compiles, obvious error - $%42); // false
Крім того, D надає деякі спеціальні ключові слова для відлагодження:
void test(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__,
string func = __FUNCTION__, string pretty = __PRETTY_FUNCTION__)
{
writefln("файл: '%s', рядок: '%s', модуль: '%s',\nфункція: '%s', гарна функція: '%s'",
file, line, mod, func, pretty);
}
А завдяки обчислень з командного рядка, можна забути про time
- буде
використано CTFE!
rdmd --force --eval='pragma(msg, __TIMESTAMP__);'