маленькие радости
Jun. 25th, 2014 11:40 pmЕсть вещи, которые совершенно тривиальны в динамически типизированных и в зависимотипизированных языках, но вот в куче промежуточных - привычных нам статически типизированных - или не делаются вовсе, или требуют страшных слов на букву "м" (нет, не монад). К счастью, бывают исключения. Пара примеров из свеженаписанного кода:
1.
Тут функция вызывается с 81 комбинацией типов.
2.
Эта функция помимо целого числа num принимает произвольное количество функций, производящих значения указанных при ее вызове типов. Тип каждой конкретной ф-ии из тупла makers формируется применением type-level ф-ии MakerType к переданному типу из тупла Hs. В теле ее имеется цикл, проходящий по этому набору функций, на разных итерациях вызываются разные ф-ии из этого набора, получаются значения разных типов, и дальше используются как сами эти значения, так и имена их типов.
Что приятно, что тут не возникает раздумий о макросах и метапрограммировании, все пишется довольно естественно и органично, это просто код.
1.
...
alias types = TypeTuple!(bool, int, double, char, string,
TestStruct!false, TestStruct!true, TestClass!false, TestClass!true);
foreach(t1; types)
foreach(t2; types)
testRB!(t1, t2, false)(num);
Тут функция вызывается с 81 комбинацией типов.
2.
alias MakerType(T) = T delegate();
void testHashesHisto(K, V, Hs...)(size_t num, staticMap!(MakerType, Hs) makers) {
...
foreach(i, H; Hs) {
auto h = makers[i]();
measure("# " ~ H.stringof ~ ".make_histo", (){
...
Эта функция помимо целого числа num принимает произвольное количество функций, производящих значения указанных при ее вызове типов. Тип каждой конкретной ф-ии из тупла makers формируется применением type-level ф-ии MakerType к переданному типу из тупла Hs. В теле ее имеется цикл, проходящий по этому набору функций, на разных итерациях вызываются разные ф-ии из этого набора, получаются значения разных типов, и дальше используются как сами эти значения, так и имена их типов.
Что приятно, что тут не возникает раздумий о макросах и метапрограммировании, все пишется довольно естественно и органично, это просто код.
no subject
Date: 2014-06-25 05:20 pm (UTC)no subject
Date: 2014-06-25 05:31 pm (UTC)no subject
Date: 2014-06-25 05:45 pm (UTC)Раскрутка цикла, в стиле плюсов, или дженерики, в стиле зависимотипизированных?
no subject
Date: 2014-06-25 05:57 pm (UTC)no subject
Date: 2014-06-25 06:10 pm (UTC)Значит, лёгким движением руки можно устроить компилятору комбинаторный взрыв :)
И опять же, значит, это всё header-only?
Ну ничего, ничего. Подождём 2017 года, вот затащат в std:: сахар вокруг boost::mpl, глядючи на D...
no subject
Date: 2014-06-25 06:39 pm (UTC)Всякие забавы с шаблонами - да, header-only. И хотя формально можно писать отдельно .d и .di (d interface, аналог .h) файлы, и компилятор умеет сам генерить вторые из первых, на практике этим редко пользуются, пишут просто модули в .d файлах и их импортируют.
А, важное отличие от С/С++ и их хедеров - все файлы читаются и парсятся лишь единожды, это не текстовый include.
no subject
Date: 2014-06-25 06:24 pm (UTC)А чем это по-сути отличается от макросов? Всё равно же, насколько я понимаю, генерируется код (как шаблонами на плюсах).
Просто макрос в D на D, почти то же, что и в лиспе, в целом-то, только чуть более криво :)
no subject
Date: 2014-06-25 06:44 pm (UTC)А в статических нелиспах макросы часто уж больно страшно выглядят, часто это отдельный раздел языка, слабо пересекающийся с основным. Плюс макросы часто оперируют лишь на уровне AST, а тут идет более осмысленная работа с типами, доступна всякая рефлексия. Но по механике это С++ да, просто с человеческим лицом.