Обновить

Комментарии 7

В С — тупая текстовая подстановка. Макрос не знает, что он подставляет: строку, число, половину if-а — ему всё равно.

Ну, не такая уж и тупая. Некоторое он таки может понять. Без особых проблем можно сделать макрос, который станет 1 для MACRO(42), а для MACRO(HELLO) выдаст "hi". У меня как раз статья про это есть.

Ну, так всё равно оно не будет знать разницы между signed и unsigned. Скорми в макрос не констатное значение и оно может делать совершенно не то чего ожидаешь. Из сложных операций только конкатенация да стрингификация. А уж проблемы с областью видимости так и вовсе один из наиболее болезненных кусков языка.

Всё равно ведь можно смотреть на ввод и в зависимости от него совершать разное. Да, возможности достаточно сильно ограничены. И я ни в коем случае не говорю, что они на уровне с macro_rules! везде/что сишные макросы удобны. Но это не такой слабый инструмент, как его представляют себе многие. Есть целый Boost preprecessor, metalang99 и другие библиотеки. Можно строить полноценные eDSL через него (пример). Есть и интерпретатор лямбда исчисления на нём. Вы и правда считаете это всё уровнем "тупой текстоподстановки"?

Есть и интерпретатор лямбда исчисления на нём.

Мягко говоря это не так. Интерпретатором всего этого будет компилятор Си, а не то что там написано. Есть язык noq, который по приколу взял идею Coq (который нынче стал Rocq) о перезаписях в доказательствах и позволяет проворачивать при помощи это вычисления-доказательства, правда без SAT ядра, то есть без формальной верификации. Этот пример делает ровно то же самое.

"тупой текстоподстановки"?

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

А теперь сравните эти же макросы с плюсовой рефлексией, например. Попробуйте сравнить какой-нибудь сериализатор произвольной структуры в JSON на макросах и на рефлексии. Сишные макросы вам столько свиней подложат, когда дойдёт история до сериализации тех же чисел, что мама не горюй. На шаблонах хотя бы трейтов/концептов навтыкать можно. В итоге в лучшем случае что могут предложить сишные макросы - немного синтаксического сахара, потому что в сам язык этот сахар не завезли.

Интерпретатором всего этого будет компилятор Си, а не то что там написано.

Это как сказать, что не бывает интерпретаторов на питоне, а интерпретировать будет CPython, а не что там написано.

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

Единственная причина, по которой макросы Си не тьюринг полны, - это невозможность выполняться вечно, есть "глубина рекурсии" (которая может быть очень большой), которая задаётся прямо кодом. Так чем macro_rules! лучше конкретно в этом плане? Если бы было возможно сделать некий EVAL, который бы мог бесконечно вычислять аргументы внутри себя, давая финальный результат лишь при остановке, макросы Си уже были бы тьюринг полны. Сейчас же можно в несколько строк кода задать EVAL в тысячи вызовов и более, но не бесконечно.

А теперь сравните эти же макросы с плюсовой рефлексией, например. Попробуйте сравнить какой-нибудь сериализатор произвольной структуры в JSON на макросах и на рефлексии.

Вы уж меня извините, но пример не особо к месту. Макросы в принципе не имеют у себя информации о типах. И макросы в расте тут не сильно лучше, в них всё равно нужно будет дать определение структуры текстом им. Это не нормальная информация о типе, встроенная в язык, которую можно получить той же рефлексией из C++26. И, как уже было сказано ранее, макросы Си имеют свои ограничения в плане синтаксиса (они не могут распарсить произвольный C++ код). Но если дать всю информацию им, то они могут многое вычислять.

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

Это не так. К примеру, я разрабатываю петом проект по компиляции регулярных выражений в Си через TNFA и TDFA, а работает этот компилятор через макросы Си. То лямбда исчисление Вы тоже просто "синтаксическим" сахаром назовёте?

Макросы в принципе не имеют у себя информации о типах.

Ну, у раста же есть, пусть и на основе AST, но и обычные типы afaik тоже можно подмешивать и проверять на уровне типов.

выражений в Си через TNFA и TDFA,

как минимум звучит неудобно. казалось бы позови какой-нибудь FA* regex_compile(regexp*), и потом сиди и матчи совпадения через sm_match(FA*, input* input). Зачем для этого ручками на макросах собирать FA - большой вопрос. Для пета конечно прикольно, но для реального мира сомнительная идея. Ждать ли статью от вас по теме?

То лямбда исчисление Вы тоже просто "синтаксическим" сахаром назовёте?

Учитывая что лямбда исчисление это предшественник языков программирования и ассемблеров, то это будет наоборот дешугаринг. Я верю, что можно сделать макросы, чтобы притворяться тем же ассемблером, но какую проблему это будет решать, учитывая что Си задумывался как попытка избавиться от привязки к конкретным ассемблерам?

Ну, у раста же есть, пусть и на основе AST, но и обычные типы afaik тоже можно подмешивать и проверять на уровне типов.

AST у раста это не AST у C++. Если в AST у C++ хранится полная информация о типах, шаблонах и прочем (такое у всех реализаций C++, а подругому просто нормально не сделать), то в расте один лишь синтаксис.

как минимум звучит неудобно. казалось бы позови какой-нибудь FA* regex_compile(regexp*), и потом сиди и матчи совпадения через sm_match(FA*, input* input). Зачем для этого ручками на макросах собирать FA - большой вопрос. Для пета конечно прикольно, но для реального мира сомнительная идея. Ждать ли статью от вас по теме?

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

Выглядеть будет как просто RE_COMPILE(name, h e l plus(l) plus(o)), а в итоге получится эффективный код на C, сравнимый по производительности с ручным.

Статья если и будет, то точно не скоро, т.к. мало что готово на данный момент.

Но у меня скоро выйдет другая статья по тому DSL, который приводился выше (там не всё так просто в реализации).

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

Вы не поняли. Там не код на лямбда исчислении в C переводится. Там лямбда исчисление выполняется на этапе компиляции. Так можно вполне проводить вычисления, которые будут выполнены препроцессором, а не позже при запуске.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Информация

Сайт
beget.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия