LINUX.ORG.RU
Ответ на: комментарий от monk

Только вручную сделав macroexpand. А в случае реализации шаблона, он раскрывается не по месту вызова, а на верхнем уровне. То есть, если в Common Lisp пытаться делать шаблоны через макросы, то придётся просто выполнять код при раскрытии.
И опять же, даже в лиспе макрос не может переписать кусок AST, который не находится внутри макроса (а, например, просто в этом же файле).

Ну так замену шаблонов надо не макросами делать, а более общим механизмом для переписывания AST, через который можно было бы дописывать в какое-то специально отведенное место результат раскрытия шаблонов (специализации функций и проч). И через этот же механизм можно и обычные макросы как в лиспе реализовать.

Потому что где-то добавиться реализация для конкретных типов, где-то оптимизатор сразу же выбросит реализацию и заинлайнит результат.

А каким боком раскрытие шаблонов к оптимизации? Это проблемы оптимизатора конкретного компилятора, чтобы он что-то там сумел оптимизировать, разве шаблоны дают какие-то подсказки в плане оптимизации? Допустим есть некий шаблон, результат раскрытия которого такой-то, такой же результат можно получить вручную, т.е. фактически руками написав код раскрытия (или написав свой препроцессор для этого), проделав работу за компилятор. Разве компилятор и в том и в другом случае не имеет равные возможности что-то заинлайнить?

Слабо на макросах Common Lisp сделать классы Си++?

Это лучше на переписывании AST делать.

Заменить ядро компилятора на лиспоподобное не выкинув половину оптимизаций – крайне сложно.

Оптимизаций раскрытия шаблонов? А в чем выражаются подобные оптимизации? Ну допустим вместо честного раскрытия шаблонов мы это раскрытие сделаем неким внешним препроцессором, как это помешает что-либо оптимизировать? Можно конечно какие-то хинты для компилятора генерить, типа «вот это инлайнить», «вот тут можно сделать так-то» или еще что-то вроде этого

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от monk

И хочешь сказать, что работать с этим списком
...
проще, чем со структурами (struct typedef (source dest)), (struct templ-instance (name params)), ….?

Может и не проще. Не суть.

Мне точно было б проще иметь дело с неким общим механизмом метапрограммирования, чем с кучей разнородных неполноценных ad-hoc костылей, когда шаблонами в принципе можно генерить некий код, но например нет возможности синтезировать на основе структуры новую структуру, типа

struct test
{
  int a;
  char b;
  float c;
}

GEN_NEW_STR(test, test_2, REMOVE_MEMBER(2))
// синтезируем на основе существующей структуры
// новую структуру без второго члена
struct test_2
{
  int a;
  float c;
}

Или невозможность использовать sin, cos, memmove, memcmp и кучи других функций в constexpr. sin, cos наверно можно свои написать, а вот насчет memmove, memcmp я что-то сомневаюсь...

SZT ★★★★★
()
Ответ на: комментарий от SZT

А в чем выражаются подобные оптимизации?

Например в том, что

template<class T>
const T& max(const T& a, const T& b)
{
    return (a < b) ? b : a;
}

int main()
{
   int x,y;
   ....
   ....
   c = max(x,y);
}

раскрывается в

...
  c = (x < y)?x:y;
...

а не в

int max_int(int a, int b) ...
...
c = max_int(x,y);

У компилятора, в отличие от макроса, есть полная информация о типах и контексте реализации шаблона, поэтому можно делать более умный алгоритм.

monk ★★★★★
()
Ответ на: комментарий от SZT

GEN_NEW_STR(test, test_2, REMOVE_MEMBER(2))

И как ты такое сделаешь в лиспе? Типа

(struct test (a b c))
(GEN-NEW-STR test test2 (REMOVE_MEMBER 2)) ;; должен создать (struct test2 (a c))

Напишешь GEN-NEW-STR ? В Scala теоретически возможно. Через scala.reflect.runtime вытащить список полей test и собрать новый тип.

а вот насчет memmove, memcmp я что-то сомневаюсь

Какие такие указатели ты хочешь использовать во время компиляции? Впрочем, в Scala можно.

monk ★★★★★
()
Ответ на: комментарий от monk

Например в том, что
...
раскрывается в

Можно раскрывать в что-то вроде

static inline __attribute__((always_inline)) max_int(int a, int b) ...
c = max_int(x,y);
и по сути будет тот же результат. Неубедительно.

У компилятора, в отличие от макроса, есть полная информация о типах и контексте реализации шаблона, поэтому можно делать более умный алгоритм.

Что по-сути делает компилятор? Фронт-энд крестового компилятора на вход получает исходник после сишного препроцессора, он переводит его в некое внутреннее представление, потом другая часть компилятора начинает с этим внутренним представлением что-то делать, там должен быть некий интерпретатор шаблонов, результатом работы которого будет раскрытие этих самых шаблонов, потом это все передается куда-то еще. С тем же успехом это раскрытие шаблонов можно сделать через чтение-запись AST. У нас есть ровно те же возможности чтения и анализа исходного кода, возможности получения инфы о типах и проч., что и у компилятора.

SZT ★★★★★
()
Ответ на: комментарий от SZT

https://jlongster.com/Lisp--It-s-Not-About-Macros,-It-s-About-Read

И? Можно на лиспе сделать конструкцию GEN-NEW-STR? Если предложение сводится к написанию генератора, который распарсит всю программу, заменит (GEN-NEW-STR …) на нужный код и получившийся результат откомпилирует лисповым компилятором, то это и с Си++ уже сейчас можно делать.

monk ★★★★★
()
Ответ на: комментарий от monk

Какие такие указатели ты хочешь использовать во время компиляции?

Варианты есть. Можно использовать почти такие как обычно, добавив принудительные проверки на всякие UB. В constexpr можно добавить даже malloc и free в компилтайм, никакие законы физики от этого не нарушатся.

SZT ★★★★★
()
Ответ на: комментарий от monk

то это и с Си++ уже сейчас можно делать.

А я не спорю. Только на Си++ надо парсить исходник и потом генерировать исходник с крестосинтаксисом, а это лишние сложности

SZT ★★★★★
()
Ответ на: комментарий от SZT

С тем же успехом это раскрытие шаблонов можно сделать через чтение-запись AST.

Ещё раз. У компилятора помимо AST есть вагон информации. Сам же пишешь: «он переводит его в некое внутреннее представление, потом другая часть компилятора начинает с этим внутренним представлением что-то делать». Вот это внутреннее представление не только AST.

У нас есть ровно те же возможности чтения и анализа исходного кода, возможности получения инфы о типах и проч., что и у компилятора.

Каким образом? Даже в лиспе. SBCL преобразует в (defun f (x) (declare (fixnum x)) (- x 2)) в (fixnum- x 2). Написать макрос, который будет раскрываться в разный код в зависимости от выведенного типа аргумента в лиспе невозможно. Нету у нас возможности получения инфы о типах и проч.

monk ★★★★★
()
Ответ на: комментарий от SZT

В constexpr можно добавить даже malloc и free в компилтайм, никакие законы физики от этого не нарушатся.

Если не считать того, что constexpr обязана быть чистой функцией. Потому что если написано «int a = inc(3), b = inc(3)», а inc – constexpr, то выполняться она будет один раз. Или вообще ни одного, если a и b далее не влияют на результат программы.

monk ★★★★★
()
Ответ на: комментарий от SZT

А я не спорю. Только на Си++ надо парсить исходник и потом генерировать исходник с крестосинтаксисом, а это лишние сложности

Ни то ни другое сложностью не является, так как есть готовые библиотеки. А вот парсить исходник с любым другим синтаксисом (например S-exp), но полностью поддерживающий семантику Си++ ещё сложнее.

monk ★★★★★
()
Ответ на: комментарий от monk

Ещё раз. У компилятора помимо AST есть вагон информации.

Вся эта информация выводится компилятором на основе AST, полученном в результате разбора человекочитаемого исходника.

Сам же пишешь: «он переводит его в некое внутреннее представление, потом другая часть компилятора начинает с этим внутренним представлением что-то делать». Вот это внутреннее представление не только AST.

Ну ОК, пусть будет «не только AST». Пусть это будет «AST с специальными подсказками, нужными для оптимизации» или что-то вроде того. В любом случае этот «не только AST» может быть получен из изначального AST путем определенного анализа. Раз компилятор может - можем и мы.

Написать макрос, который будет раскрываться в разный код в зависимости от выведенного типа аргумента в лиспе невозможно.

Ну так это можно не макросом делать, а копаясь в AST напрямую, через этот read. Я и не утверждал нигде, что лисповые макросы это универсальный инструмент.

SZT ★★★★★
()
Ответ на: комментарий от monk

А вот парсить исходник с любым другим синтаксисом (например S-exp), но полностью поддерживающий семантику Си++ ещё сложнее.

А нужно ли вообще к этому стремиться? Полностью поддерживать семантику C++ не осиливают даже создатели компиляторов

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51577 например этот баг живет аж с 2011 года, чего-то там в неймспейсе находит, но не должно находить.

Или вот «Virtual-base class class constructor with for-loop with initializer list referencing local variable not executed» https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88517

Может ну его в пень? Семантика С++ это явно не предел совершенства. Не идеал, к которому стоит стремиться.

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Раз компилятор может - можем и мы.

Можем. Написав ещё один компилятор. Когда den73 пытался свой Яр на базе SBCL написать, то где-то на этом этапе и отчаялся.

Ну так это можно не макросом делать, а копаясь в AST напрямую, через этот read. Я и не утверждал нигде, что лисповые макросы это универсальный инструмент.

Копировать 90% компилятора в свой обработчик, чтобы написать конструкцию типа GEN-NEW-STR — это ещё меньше инструмент.

Вот есть, например, реализация множественной диспетчеризации. Алгоритм известен, но внести нужные изменения, например, в gcc могут всего дюжина человек в мире. И им это не надо. А всем остальным проще механизм Посетителя использовать.

monk ★★★★★
()
Ответ на: комментарий от SZT

А нужно ли вообще к этому стремиться? Полностью поддерживать семантику C++ не осиливают даже создатели компиляторов

Без семантики C++ это будет другой язык, несовместимый с C++ по библиотекам. Тогда проще использовать тот же Racket, например.

например этот баг живет аж с 2011 года

Есть ещё clang. Может там его нет.

monk ★★★★★
()
Ответ на: комментарий от monk

И сравни, сколько времени потрачено будет на сборку той же версии, но с макросом, и твоей - на шаблонах!

Как же эти плюсеры достали со своими шаблонами и прочими закидонами! 20 страниц кода у них по пять минут компиляется! Это ли не издевательство над людьми?

OnlyAsk
()
Ответ на: комментарий от OnlyAsk

Как же эти плюсеры достали со своими шаблонами и прочими закидонами! 20 страниц кода у них по пять минут компиляется! Это ли не издевательство над людьми?

На лисповых макросах легко сделать компиляцию ещё дольше. И где это 20 страниц кода 5 минут компилируются? Может их приведёшь?

monk ★★★★★
()
Ответ на: комментарий от monk

Есть ещё clang. Может там его нет.

Может нет, зато будут другие косяки. Можно покопаться в багзилле, там точно что-то есть. Пока что нет в природе компилятора, полностью соответствующего семантике крестов, притом несоответствия наверняка будут даже в каком-нибудь протухшем стандарте C++99.

SZT ★★★★★
()
Ответ на: комментарий от SZT

Можно покопаться в багзилле, там точно что-то есть. Пока что нет в природе компилятора, полностью соответствующего семантике крестов, притом несоответствия наверняка будут даже в каком-нибудь протухшем стандарте C++99.

Как-то бездоказательно. Ну ладно, у каждого своя вера.

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.