Comments 29
И опять магия и трюки. В языке D конечно учтены многие ошибки дизайна C++, но метапрограммирование все так-же натянуто — впечатление, что его прикручивали уже после разработки языка.
+2
Мне не нравится разделение типов и значений, но если их приравнивать, то получается система с зависимыми типами. Развитие в эту сторону мне кажется логичным.
Также напрягают шероховатости при получении информации от компилятора, она просто нетипизирована, пока не обернута в список. Есть другой подход через вызов обычных функций во время компиляций, но он не может оперировать типами напрямую, только строками. Шаблонный подход более элегантный.
Знаком еще с Template Haskell, там оперируешь с AST, это по мощности где-то посередине между примесями и шаблонами. Я бы его не назвал удобным, опасность чуть ниже примесей, а удобства не прибавляет.
Также напрягают шероховатости при получении информации от компилятора, она просто нетипизирована, пока не обернута в список. Есть другой подход через вызов обычных функций во время компиляций, но он не может оперировать типами напрямую, только строками. Шаблонный подход более элегантный.
Знаком еще с Template Haskell, там оперируешь с AST, это по мощности где-то посередине между примесями и шаблонами. Я бы его не назвал удобным, опасность чуть ниже примесей, а удобства не прибавляет.
0
Мне нравится подход языка Nemerle. Там есть «макросы» — специальные функции, начинающиеся с ключевого слова «macro». По сути это функции, выполняющиеся во время компиляции. В них можно обычным императивным способом выполнять код, который имеет доступ к API компилятора. Этим функциям можно передать объекты кода в виде AST-деревьев. С одной стороны, никаких строк — с другой стороны, никакой шаблонной магии.
А что вы имеете в виду под «разделение типов и значений»? Я наверное не знаком с зависимыми типами, интересно что это такое.
А что вы имеете в виду под «разделение типов и значений»? Я наверное не знаком с зависимыми типами, интересно что это такое.
+1
А что вы имеете в виду под «разделение типов и значений»?
Если аргумент значение, то используется enum, если тип, то alias. Осталось совсем немного, чтобы оперировать с типами как с значениями. На словах это будет все равно непонятно, вот пример из Idris:
(++) : Vect n a -> Vect m a -> Vect (n + m) a
(++) Nil ys = ys
(++) (x :: xs) ys = x :: xs ++ ys
Главная мысль — в сигнатуре вектора используется значение его длины, поэтому тип как бы «зависит» от своих значений, добавил новый элемент в вектор — тип изменился. Также видно, что даже в сигнатуре функции происходят некие вычисления. Возможно, это самый органичный способ вписать мету в язык. Увы я знаю о зависимых типах не так уж много, чтобы делать какие-то выводы.
Там есть «макросы» — специальные функции, начинающиеся с ключевого слова «macro». По сути это функции, выполняющиеся во время компиляции. В них можно обычным императивным способом выполнять код, который имеет доступ к API компилятора. Этим функциям можно передать объекты кода в виде AST-деревьев. С одной стороны, никаких строк — с другой стороны, никакой шаблонной магии.
Но это же получается boilerplate код, от D подхода при генерации через compile-time function evaluation не отличается (нужно заметить, что в D не полностью строковой подход, можно примешивать только целые expressions или объявления).
+1
Макросы и шаблоны реально оперируют не типами и не значениями, а фрагментами AST. То что традиционно шаблоны в С++ в качестве аргументов получают исключительно типы и значения (почему-то только целочисленные) — это ИМХО недоразумение. У меня при работе с низкоуровневым программингом для микроконтроллеров не раз возникала необходимость сделать шаблон, в который можно было бы передать просто фрагмент кода (даже не функцию, а просто код в фигурных скобках). Приходилось делать костыли с сишными лексическими макросами, которые как вы понимаете, далеко не лучшее решение в программировании.
Поэтому все эти alias и enum в D воспринимаются как унаследованные от С++ костыли. Конечно, должен быть некий механизм ограничения того, что мы передаем в шаблон — если там предусмотре тип, то это должен быть только тип а не что угодно. Но на самом верхнем уровне это именно нода синтаксического дерева.
Поэтому все эти alias и enum в D воспринимаются как унаследованные от С++ костыли. Конечно, должен быть некий механизм ограничения того, что мы передаем в шаблон — если там предусмотре тип, то это должен быть только тип а не что угодно. Но на самом верхнем уровне это именно нода синтаксического дерева.
0
Через alias параметры можно передавать символы, это, конечно, не целое AST, но уже его часть. Разработчики заняли довольно принципиальную позицию о том, что вместо операций над AST удобнее собирать строки и примешивать. Максимум, что можно ожидать в будущих версиях — расширение traits возможностью получать AST в виде списка-дерева из строк и работать с ним через compile-time функции.
0
Макросы обсуждались ещё на первом DConf в (страшно представить!) 2007 году, с тех пор в языке существует ключево слово «macro», которое на практике не используется. Со временем было принято решение что генерация кода через CTFE/mixin — решение более универсальное и простое для изучения новичками, хотя и существенно уступающее в гигиене для более сложных проектов. На данный момент введение AST макросов не рассматривается, DIP50 — просто мысли одно из активных участников сообщества.
В целом макросы вещь важная и нужна, но не столь однозначно превосходящая CTFE/mixin, как может показаться. Преобразование существующего кода — да, тут вопросов не возникает. Но поддержка произвольных строковых DSL куда проще реализуется простым лексическим разбором этих самых DSL.
Лично мне в текущей системе не хватает аргументов-выражений (по аналогии с тем, как alias это аргумент-символ), это решило бы множество задач, где пригодились бы макросы.
В целом макросы вещь важная и нужна, но не столь однозначно превосходящая CTFE/mixin, как может показаться. Преобразование существующего кода — да, тут вопросов не возникает. Но поддержка произвольных строковых DSL куда проще реализуется простым лексическим разбором этих самых DSL.
Лично мне в текущей системе не хватает аргументов-выражений (по аналогии с тем, как alias это аргумент-символ), это решило бы множество задач, где пригодились бы макросы.
+1
Нужно заметить, что сложные грамматики не запихнешь в compile-time, не хватает памяти. Распарсить D код с модификациями не получится без серьезной доработки эффективности CTFE.
0
Это дефект реализации CTFE, фундаментально тут никакой проблемы нет. Всего лишь исправление issues.dlang.org/show_bug.cgi?id=6498 уменьшит потребление памяти на порядок и больше.
Экспериментальный альтернативный front-end для D (https://github.com/deadalnix/SDC) использует LLVM JIT для CTFE и вообще не имеет таких проблем :)
Экспериментальный альтернативный front-end для D (https://github.com/deadalnix/SDC) использует LLVM JIT для CTFE и вообще не имеет таких проблем :)
+1
Думал, что SDC заглох. Меня он привлекает в первую очередь как compiler as a library, можно было бы использовать D как встраиваемый скриптовый язык.
0
Нет, он очень даже жив. deadalnix выступал с презентацией на недавнем DConf: dconf.org/2014/talks/sechet.html + планируется в качестве одной из заявок на GSoC.
Видео с конференции правда придётся ждать долго, т.к. выступал он последним, а публикуют их по порядку :) Но архитектура намного более перспективная, чем жуткая каша в исходниках DMD.
Видео с конференции правда придётся ждать долго, т.к. выступал он последним, а публикуют их по порядку :) Но архитектура намного более перспективная, чем жуткая каша в исходниках DMD.
+1
Что люди не делают, только чтобы не познавать Haskell… Я когда-то был в эйфории от метапрограммирования на C++, но после Haskell это смешно и неудобно.
-1
Можно пояснить, что именно вы имели ввиду? Я познал Haskell на среднем уровне и не помню там меты, кроме банальных вычислений на типах (Nat и вектора на них) и TH, который требует отдельного прогона компилятора, оперирует AST и с легкостью получает невалидный код.
Тем более, почему бы императивным языкам не иметь элементы функционального подхода в мете, если это удобно и zero-cost для производительности? На Haskell нужно специально затачивать код под производительность, зачастую теряя в читаемости.
Тем более, почему бы императивным языкам не иметь элементы функционального подхода в мете, если это удобно и zero-cost для производительности? На Haskell нужно специально затачивать код под производительность, зачастую теряя в читаемости.
0
template Tuple(T...)
{
alias Tuple = T;
}
Пожалуйста, не надо использовать термин Tuple (кортеж) для обозначения списка шаблонных аргументов в D. Это очень специфическая для языка сущность, с огромным количеством особенностей и заморочек, почти ничего общего с кортежами из других языков не имеющая. На дальнейшие объяснения «почему так, а не эдак» приходится тратить очень много времени.
Ссылка по теме: wiki.dlang.org/DIP54
0
Ни разу не видел эту рекомендацию. Называть их «TemplateArgumentList» — ужасное решение, весь код разбухнет раза в 3-4, а делать alias на тот же Tuple (или другое короткое имя, мб ETuple) — костыль.
0
Разбухание кода 1-5% разработчиков, которые активно использует метапрограммирование — терпимая цена за упрощение документации для всех остальных. Это я говорю как тот самый разработчик, чей код может разбухнуть :) В любом случае, имя Tuple уже используется стандартной библиотекой для std.typecons.Tuple, поэтому этот вариант вообще недопустим в обучающих материалах.
Кстати рекомендуемый короткий alias — List и Pack соответственно.
Кстати рекомендуемый короткий alias — List и Pack соответственно.
+1
Спасибо, List и Pack действительно лучше. Переведу код на них.
P.S. Меня никогда не смущало наличие второго «Tuple» в std.typecons, т.к. все попытки его использовать разбивались о плохую поддержку IDE и проблемы с сериализацией, а еще он не работает с immutable.
P.S. Меня никогда не смущало наличие второго «Tuple» в std.typecons, т.к. все попытки его использовать разбивались о плохую поддержку IDE и проблемы с сериализацией, а еще он не работает с immutable.
0
В std.typetuple уже есть private Pack и он не является по смыслу 'StrictTuple', итого dmd не позволяет мне использовать название Pack.
0
Да, DIP54 ещё не закончен (я работаю над этим по мере свободного времени), пока что в «живых» проектах приходится выкручитываться на свой вкус. Я изначально говорил только об учёбных материалах, вводящих в заблуждение.
0
Ещё один мой DIP на эту же тему: wiki.dlang.org/DIP63
0
Стоящее предложение. Почему бы тогда не сделать alias с параметрами доступными не только в шаблонах?
0
Не понял вопроса :)
0
У меня устаревшие сведения, полгода назад не мог делать параметризированные alias:
/// Alias for vector of 2 elements
alias vec2(T) = Vector!(T, 2);
/// Alias for vector of 3 elements
alias vec3(T) = Vector!(T, 3);
0
Простите за тупые вопросы но как мне сделать глобальный мутабельный обьект-структуру?
struct Predmet{ x: int }
в функции я пишу так:
let predmet = Predmet{ x: 15};
а как зделать вне функции чтобы глобально?
struct Predmet{ x: int }
в функции я пишу так:
let predmet = Predmet{ x: 15};
а как зделать вне функции чтобы глобально?
0
struct Predmet { int x; }
Predmet globalPredmet = Predmet(15);
unittest
{
std.stdio.writeln(globalPredmet);
}
Или, если нужны сложные вычисления для создания структуры, то можно через конструктор модуля:
struct Predmet { int x; }
Predmet globalPredmet;
static this()
{
globalPredmet = Predmet(15);
}
unittest
{
std.stdio.writeln(globalPredmet);
}
0
Sign up to leave a comment.
Compile-time функциональное программирование в D