#define MANAGED_STRUCT_NAME Person // определяем макрос, который задает имя// структуры
BEGIN_MANAGED_STRUCT // определяем начало структурыMANAGED_FIELD(std::string, name) // определяем поле с типом 'std::string'и именем// 'name'MANAGED_FIELD(int, age) // определяем поле с типом 'int' и именем 'age'MANAGED_FIELD(bool, student) // определяем поле с типом 'bool' и именем// 'student'
END_MANAGED_STRUCT // определяем конец структуры#undef MANAGED_STRUCT_NAME // убираем макрос, который задавал имя структуры,// чтобы не было варнингов о переопределении// макроса в дальнейшем
Если бы там не было interior mutability, был бы прекрасный язык. Растоманам пришлось кучу костылей из-за неё навернуть и даже mem::forget сделать сейфовой функцией.
Блин, от этого словосочетания повеяло холодом… Надеюсь, жадные потные ручонки мелких не дотянутся.
И не понимаю, чего добивается Царь, но именно форма его высказываний побудила меня серьёзно заинтересоваться Растом — по принципу «значит, хорошая вещь, надо брать». И я, признаться, очарован. Классный язык, идейный. Уважаю идейных.
Ксати, здесь мы можем заметить новую методичку птушников. Хотя, она не новая, ей уже лет пять точно есть. Как только клоуну нечего ответить - она начинает кричать про «царя», подавая сигнал другим балаболам и призывая их на помощь. В итоге уже через несколько постов болезные полностью ломаются и спамят ахинею вида «ололо, царь», выдавая это за аргумент. Ошибка бездарей в том, что я не царь, и со мной такое не пройдёт
Как было озвучено выше, первый пример это не руст. Это строка, которая парсится васянским парсером перед компиляцией. После чего старой доброй склейкой строчек, рядом со структурой «генерятся» имплементации нужных трейтов
Потомучто для функций Serialize, Deserialize, пафосно запихнутых в квадратные скобочки, нет никакой структуры. На вход эти функции получают строку в виде TokenStream. На выходе тоже строка, которая заменит входную строку на этом месте в файле. А дальше е**тесь как хотите. Это даже не сишный define. В define хоть какой-то синтаксис есть
Я таким непотребством в начале века занимался при помощи M4 и make-файлов. И сейчас иногда грешу на бабеле. Но как-то не приходило в голову называть это «процедурными макросами». Скорее днищем. А тут в 2020 мэйк-файл встраивают в исходник и все сразу писают кипятком. «Most loved language», хех
Я бы так не бомбил, если б эта фича шла боком, никого не трогала. Так нет, б**ть, в каждом первом проекте. Потом жалуются, чегой-то у нас компиляция медленная и папка таргет размером с игру
Где-то на просторах ютуба есть интервью с поцыком из jetbrains, разрабатывающим плагин для раста. Он тоже без купюр называет макросы раста днищем
И чем плохи строковые миксины и кодогенерация на их основе?
Прекрасно. Просто замечательно. В ЯП 2 вида макросов, и оба недалеко ушли от PHP. Строковые миксины, е**ть
Представь, ты компилятор. Ты распарсил исходник, разобрал полочкам все конструкции. Этот разобранный лежит AST у тебя в памяти прям, пряи тут, на расстоянии одного сискола. И тут встречается тебе «атрибут» Serialize и ты такой: «а, пох, вот ему строка пусть сам трахается, заново всё парсит»
Тебя в таком виде выкатывают в прод и куча школьников, не разобравшись, начинают вопить «i love rust» и радостно обмазываются этими атрибутами
Рискну предположить, что как и async, макросы еще не доделаны и потом сделают норм. Но код-то пишут уже сейчас. И переписывать это потом никто не будет
Derive создаёт точно такую же функцию, которую ты бы написал руками, и ничего не замедляет. Особенно по сравнению рефлексией какой-нибудь. Есть макросы, которые весь язык переписывают, ну так не пользуйся такими, пиши всё вручную.
Derive создаёт точно такую же функцию, которую ты бы написал руками
Что это вообще значит? Что значит «такую же функцию, которую ты бы написал руками»? Сидя в трусах перед монитором и смотря паралельно «Время Приключений»?
Этот разобранный лежит AST у тебя в памяти прям, пряи тут, на расстоянии одного сискола. И тут встречается тебе «атрибут» Serialize и ты такой: «а, пох, вот ему строка пусть сам трахается, заново всё парсит»
Что это вообще значит?
Есть, например, трейт для дебажных строк. 99% случаев тебе плевать, как именно эта строка выглядит. Поэтому в 99% случаев ты будешь писать в точности то же самое, что указано в доке.
https://doc.rust-lang.org/std/fmt/trait.Debug.html#tymethod.fmt
Поэтому и сделали макрос, который делает в точности то же самое. Полученная функция в ассемблере и IR будет выглядеть также, как написанная вручную.
Только такие и есть
Я видел только Fehler, инлайновый JSON и инлайновый GLSL. В каждом из случаев это такое мелкое удобство, а не что-то, без чего ну никак не обойтись.
Ну так предложи нормальную замену. Хотя бы на уровне java-аннотаций
Я не знаю, что тебе надо. Конкретно в случае serde есть аналог, который делает всё то же самое, но через динамик диспатч. Он, вроде бы, собирается быстрее. А джава аннотации требуют рантайма и для целей раста не подходят.
Ну то-есть, признал-таки, что раст макросы днище
Они исполняют свою задачу: автоматизировать рутинные задачи без использования всякой неявной магии и без дополнительных накладных расходов в рантайме. Это сложная задача, которую нельзя решить легко, просто, эффективно и быстро одновременно.
Как и любая другая абстракция, макросы могут быть неадекватны задаче, которую ты пытаешься решить. Я допускаю, что от трех тысяч #[Derive(Serialize)] компилятору может поплохеть. Значит придётся что-то придумывать. Например, для части объектов писать сериализацию вручную, таким образом смещая сложность с компилятора на человека. Это и есть программирование, выбор правильных компромисов.
Компилятор с одними структурами работает, но наружу отдаёт «строку», которая парсится в другие структуры
Адаптеры и версионирование никто не отменял
Называть пердолинг со строками процедурными макросами означает намеренно вводить школьников в заблуждение
Я тут недавно запилил скрипт, превращающий CSV файл JS файл с массивом объектов. Оказывается я добавил в JS процедурные макросы. Отправлю предложение в TC39. Не благодарите
Так они и сделали, в некотором роде, адаптеры: ты ведь не совсем со строками работаешь. То, что там между компилятором и syn строка - ну и ладно.
Но всё-таки, макросы довольно долго были «нестабильными» и доступными только в найтли. Когда стало понятно, что часть инфраструктуры из-за этого не может на стейбл переехать, то стали что-то делать. Такой вот компромисс. Ресурсов на то чтобы сделать всё и сразу нормально у них явно не хватает. macro_rules вон тоже проблемы имеет, специализацию не осилили доделать и т.д.
Не идеально, зато такое решение позволило побыстрее стабилизировать макросы. Может когда-то нормально сделают.
В D вообще тупо строки подмешивают https://tour.dlang.org/tour/en/gems/string-mixins
В rust наверно тоже можно было наружу отдать такой же механизм, было бы для простых случаев проще и удобнее чем процедурные макросы.
Если syn встроить в компилер, то и компиляция ускорится и каждый проект не будет собирать пол компилятора в папке target. Для генерации тоже можно какой-то интерфейс замутить, чтоб не позориться со «строковыми миксинами»
Если syn встроить в компилер, то и компиляция ускорится и каждый проект не будет собирать пол компилятора в папке target. Для генерации тоже можно какой-то интерфейс замутить, чтоб не позориться со «строковыми миксинами»
Все это давно придумано, просто надо работать с AST, а не токенами. В лиспе это легко получается из-за того что лисп это как-раз голый AST прикидывающийся языком программирования, для компилируемых языков лучшая реализация в nemerle.org
В лиспе это легко получается из-за того что лисп это как-раз голый AST прикидывающийся языком программирования
Почитайте про lisp curse. Именно поэтому в D используются не очень удобные строковые миксины, а AST макросы под запретом. AST макросы очень мощный инструмент, который позволяет изменять синтаксис языка и это приводит к тому, что любой проект, использующий AST макросы становится диалектом языка с той или иной степенью несовместимости с остальными.
Вы опять тут срётесь? И почему-то никто не может продолжить поднятую мною тему.
Упомянутая задача состоит из двух базовых подзадач. Генерация мета-инфы для интроспекции + генерации на базе этой инфы всяких реализация чего угодно.
Дак вот, фундаментальное отличие С++ от недоязычках типа раста(и другого мусора) в том, что как и С++ они не могут в интроспекцию, но. С++ может сгенерировать из мета-информации реализации. Т.е. если мы для С++ введём некую магическую функцию:
f(T) -> accessor<T> - С++ сможет сгенерировать что угодно. Хоть сериализацию, хоть десериализацию.
Говнораст(и прочая скриптуха с мусорной системой типов) эту функцию попросту даже выразить не может. Аналогично не сможет ничего с ней сделать, даже если мы предположим, что её выразить можно.
Именно для этого недоязычкам и нужна кодогенерация, что-бы генерировать конечные реализации, т.е. ser(T) -> string и т.д.
Я накатал базовый пример вам - https://godbolt.org/z/nvgpFG - этого достаточно, что-бы С++ мог сделать что угодно.
Т.е. нужно сгенерировать всего лишь специализацию для point:
Соответственно, мы видим как делается это у нормальных людей. Никаких строк. Код как данные, данные как код, код как генератор.
И это в С++, в языке, который сложнее всего мусора вместевзятого. Там достаточно много костылей из-за этого. Шланг слишком говно, разобраться как там что захватывается в С++ - невозможно. У них был баг на баге из-за этого. Поэтому пришлось захваты прописывать руками. Такого там много.
Но всем насрать, потому как это передовые разработки. Нигде более подобного нет, а что есть - примитивная херня.
И весь этот код тайпчекается, все его части тоже. Семантика такая же, как у шаблонов.
Это нужно чтобы не стабилизировать AST компилятора и не связывать разработчикам руки (слишком сильно).
Причём тут ast? Всё это должно быть на уровне языка. Но у недоязычка нет языка, в этом проблема. Поэтому приходится прикручивать строки, внешнюю логику и прочее.
Компилятор с одними структурами работает, но наружу отдаёт «строку», которая парсится в другие структуры, а потом обратно в строку.
Ему ничего не нужно отдавать. Ты всё перепутал. Дело в том, что мусорный недоязычок не может выразить string -> T и в этом проблема. Поэтому с обоих сторон типы должны быть затёрты.
Не идеально, зато такое решение позволило побыстрее стабилизировать макросы. Может когда-то нормально сделают.
Быстро? За это время шангл/хром написали. К тому же это полная чушь. Никакой стабилизации нет и она никому не интересна. Потому что никто в этой бездарной поделки за неё не отвечает.
И никогда нормально оно быть сделано не может. Адепты слишком тупые и им это не доступно по определению, их недоязычок такое же дерьмо. Т.е. нужно родить и адептов и недоязычок заново. Но если адептов родить заново и у них появится мозг - они никогда в раст не пойдут. Зачем кому-то состоятельному копаться в дерьме и производить его?
Поэтому и сделали макрос, который делает в точности то же самое. Полученная функция в ассемблере и IR будет выглядеть также, как написанная вручную.
Полная чушь. Макросня используется там, где недоязычок не смог.
Я не знаю, что тебе надо. Конкретно в случае serde есть аналог, который делает всё то же самое, но через динамик диспатч. Он, вроде бы, собирается быстрее. А джава аннотации требуют рантайма и для целей раста не подходят.
Зачем ты несёшь херню ничего не зная? java-аннотациям не нужно работать в рантайме. К тому же твоё дерьмо и работает в рантайме, что же ты такой тупой?
Они исполняют свою задачу: автоматизировать рутинные задачи без использования всякой неявной магии и без дополнительных накладных расходов в рантайме.
Опять сектант перданул в лужу. Это и есть неявная магия -ты обделался. И дополнительные расходы в рантайме там есть. От того я и валял в дерьме сектанта с serde.
Это сложная задача, которую нельзя решить легко, просто, эффективно и быстро одновременно.
Можно, но не бездарностям. К тому же она решена в С++ - ты обгадился.
Написать свой макрос или прочитать чужой - это задача для людей, в отличие от того инопланетного п-ца, который царь приводил как пример божественности Плюсов:
Клоун нелепый - это не плюсы. И тебе, идиоту, сообщили, что эти макросы выполняют разную задачу. И то, что делает твой говнерде - макросами делать не нужно.
И тут ты обгадился - в сишных макросах запрещена рекурсия. Специально запрещена. Всё то, что ты показываешь, тупой сектант - это костыли, для прикрутки в макросам рекурсии для реализации вариадик.
Ни одного ни второго у тебя, сектант, нет. И этот макрос, бездарность, никакой логики не реализует.
Как и любая другая абстракция, макросы могут быть неадекватны задаче, которую ты пытаешься решить.
Нет, клоун. Ты обгадился, опять. Макросы - дерьмо, всегда.
Я допускаю, что от трех тысяч #[Derive(Serialize)] компилятору может поплохеть.
Нет, клоун. И тут ты обгадился. Проблема не в этом, а в том, что у тебя код генерирует дерьмо. А в С++ он генерируется компилятором при помощи генераторов, написанных на С++.
Значит придётся что-то придумывать. Например, для части объектов писать сериализацию вручную, таким образом смещая сложность с компилятора на человека. Это и есть программирование, выбор правильных компромисов.
Нелепая херня. Ты не напишешь сериализацию вручную, жертва пропаганды. Именно для этого тебе и нужен кодоген. А ни для чего другого.
Именно поэтому в D используются не очень удобные строковые миксины
Не поэтому. Тебя поимела пропаганда. Просто хомячьё ничего другого не осилило.
В лиспе нет никакого ast, нет никакого ast. И нет вообще никакого лиспа. Зачем вы, сектанты, каждый раз повторяете нелепую херню, ничего не зная?
AST макросы очень мощный инструмент, который позволяет изменять синтаксис языка и это приводит к тому, что любой проект, использующий AST макросы становится диалектом языка с той или иной степенью несовместимости с остальными.
Это не является проблемой, к том уже это базовое свойство любого языка с мощным синтаксис - его синтаксис обобщённый. Поэтому С++ и является С++.
А в лиспе нет языка, не синтаксиса. Это примерно как кукарекать, что ввод нового тега в html - ввод нового синтаксиса.
Дак вот, лисп такой же html, json и любая подобаная рекурсивная структура данных. Очевидно, что семантическая структура данных произвольна. И её можно интерпретировать как угодно.
Но это мусор, который никому не интересен и ничего не значит.
Ну ты реально обделался. Зачем ты показываешь всю ограниченность плюсов? Про твою мы и так знаем. Всю твою кучу кода на других языках и писать не придется. Вот вариант на D:
import std.stdio;
struct point {
double x, y;
}
void main() {
auto p = point(123, 1234);
stderr.writeln(p.x);
p.x = 321;
stderr.writeln(p.x);
stderr.writeln(p.y);
stderr.writeln(__traits(identifier, p.x));
stderr.writeln(__traits(identifier, p.y));
}
код полностью аналогичен твоему примеру и намного короче, чище и понятнее что новичку, что эксперту. нет нужды вручную что-то прописывать или дополнительно как-то генерировать мета-информацию, использовать макросы. Только эти четыре ужасных строчек чего стоят:
Ну ок, ты их просто для иллюстрации своего акссесора привел. Так вот на том же D никаких акссесоров не нужно от слова вообще. В общем пример у тебя неудачный от слова совсем. У тебя вручную нужно писать метаинформацию, ни в D, ни в Расте этого делать не нужно.
import std.stdio;
struct point {
double x, y;
}
void main() {
auto p = point(123, 1234); // создаем экземпляр структуры
stderr.writeln(p.tupleof[0]); // обращаемся на чтение к члену структуры по ее порядковому номеру - 0 это point.x, 1 это point.y
p.tupleof[0] = 321; // обращаемся на запись к члену структуры по ее порядковому номеру, а не по имени// обращаемся ко всем полям структуры по их номеру// в компайл таймеstaticforeach(i; 0..p.tupleof.length)
stderr.writeln(p.tupleof[i]);
// с помощью трейта получаем значение идентификатора// поля структуры по его номеру
stderr.writeln(__traits(identifier, p.tupleof[0]));
stderr.writeln(__traits(identifier, p.tupleof[1]));
}