Если что-то может быть сгенерировано, то это данные, а не код.
Учитывая это, не является ли вся эта идея генерации исходного кода недоразумением? То есть, если для чего-то есть генератор кода, то почему бы не сделать это чем-то надлежащим образом, чтобы оно могло получать требуемые параметры и выполнять правильные действия, которые мог бы выполнить «сгенерированный» код?
Если это делается по соображениям производительности, то это звучит как недостаток компилятора.
Если это делается для объединения двух языков, то это звучит как отсутствие интерфейса библиотеки.
Я что-то здесь упускаю?
Я знаю, что код тоже данные. Что я не понимаю, зачем генерировать исходный код ? Почему бы не превратить это в функцию, которая может принимать параметры и воздействовать на них?
flex
или синтаксический анализатор, сгенерированный с помощьюbison
почти наверняка будет более предсказуемым, более правильным и часто более быстрым в выполнении, чем эквиваленты, написанные от руки на C; и построен из гораздо меньшего количества кода (таким образом, также меньше работы для обслуживания).Ответы:
Технически, если мы генерируем код, он не является источником, даже если это текст, который читается человеком. Исходный код - это оригинальный код, созданный человеком или другим истинным интеллектом, механически не переведенный и не воспроизводимый немедленно из (истинного) источника (прямо или косвенно).
Я бы сказал, что все равно данные . Даже исходный код. Особенно исходный код! Исходный код - это просто данные на языке, предназначенном для выполнения задач программирования. Эти данные должны быть переведены, интерпретированы, скомпилированы, сгенерированы, при необходимости, в другие формы - данных - некоторые из которых оказываются исполняемыми.
Процессор выполняет инструкции из памяти. Та же самая память, которая используется для данных. Перед тем, как процессор выполнит инструкции, программа загружается в память как данные .
Итак, все данные , даже код .
Прекрасно иметь несколько этапов компиляции, один из которых может быть промежуточной генерацией кода в виде текста.
Это один из способов, но есть и другие.
Не все текстовые формы предназначены для потребления человеком. В частности, сгенерированный код (как текст) обычно предназначен для потребления компилятором, а не для использования человеком.
Исходный код считается оригинальным: мастер - что мы редактируем и разрабатываем; что мы архивируем, используя контроль исходного кода. Сгенерированный код, даже когда текст читается человеком, обычно восстанавливается из исходного исходного кода . Вообще говоря, сгенерированный код не должен находиться под контролем исходного кода, поскольку он восстанавливается во время сборки.
источник
Практические рассуждения
Из этого редактирования я предполагаю, что вы спрашиваете на довольно практическом уровне, а не на теоретической информатике.
Классическая причина генерации исходного кода на статических языках, таких как Java, заключалась в том, что в таких языках просто не было простых в использовании языковых инструментов для создания очень динамичных вещей. Например, еще в дни становления Java просто не было возможности легко создать класс с динамическим именем (сопоставление имени таблицы из БД) и динамическими методами (сопоставление атрибутов из этой таблицы) с динамическими типами данных (сопоставление типы указанных атрибутов). Тем более, что Java придает большое значение, а может быть, и гарантирует возможность распознавать ошибки типов во время компиляции.
Таким образом, при такой настройке программист может только создавать код Java и писать много строк кода вручную. Часто программист обнаруживает, что всякий раз, когда таблица изменяется, он должен вернуться и изменить код для соответствия; и если он забудет об этом, случатся плохие вещи. Следовательно, программист доходит до того, что он пишет некоторые инструменты, которые делают это для него. И, следовательно, дорога к все более интеллектуальному генерированию кода.
(Да, вы можете сгенерировать байт-код на лету, но программирование такой вещи на Java не было бы чем-то, что случайный программист делал бы просто между написанием нескольких строк кода домена.)
Сравните это с очень динамичными языками, например, Ruby, который я в большинстве случаев считаю противоположностью Java (обратите внимание, что я говорю это, не оценивая ни один из подходов; они просто разные). Здесь на 100% нормально и стандартно динамически генерировать классы, методы и т. Д. Во время выполнения, и, самое главное, программист может делать это тривиально прямо в коде, не переходя на «мета» уровень. Да, такие вещи, как Ruby on Rails, сопровождаются генерацией кода, но в нашей работе мы обнаружили, что мы в основном используем это как своего рода расширенный «режим обучения» для новых программистов, но через некоторое время это становится излишним (так как кода так мало написать в этой экосистеме, что, когда вы знаете, что делаете, написание этого вручную становится быстрее, чем очистка сгенерированного кода).
Это всего лишь два практических примера из «реального мира». Тогда у вас есть языки, такие как LISP, где код буквально является данными. С другой стороны, в скомпилированных языках (без движка времени выполнения, таких как Java или Ruby), (или я не следил за современными возможностями C ++ ...) просто нет концепции определения имен классов или методов во время выполнения, поэтому генерация кода процесс сборки является инструментом выбора для большинства вещей (другие, более специфичные для C / C ++ примеры, такие как flex, yacc и т. д.).
источник
Потому что программирование перфокартами (или альтернативными кодами в блокноте ) - это боль.
Правда. Я не забочусь о производительности, если я не вынужден.
Хмм, понятия не имею, о чем ты.
Похоже, это так: генерируемый и сохраняемый исходный код всегда и навсегда является болью в заднице. Он существует только по одной причине. Кто-то хочет работать на одном языке, в то время как кто-то настаивает на работе на другом, и никто не может быть обеспокоен, чтобы выяснить, как взаимодействовать между ними, поэтому один из них выясняет, как превратить свой любимый язык в навязанный язык, чтобы они могли делать то, что они хотят.
Что хорошо, пока я не буду поддерживать это. В этот момент вы все можете умереть.
Это анти паттерн? Вздох нет Многие языки даже не существовали бы, если бы мы не были готовы попрощаться с недостатками предыдущих языков, а генерация кода старых языков - это то, сколько новых языков начинаются.
Это кодовая база, оставленная в полуконвертированном лоскутном одеянии монстра Франкенштейна, которое я терпеть не могу. Сгенерированный код является неприкасаемым кодом. Я ненавижу смотреть на неприкасаемый код. Все же люди продолжают проверять это. ПОЧЕМУ? Вы также можете проверить исполняемый файл.
Ну, теперь я ругаю. Я хочу сказать, что мы все "генерируем код". Когда вы относитесь к сгенерированному коду как к исходному, вы сводите меня с ума. Просто потому, что он выглядит так, как будто исходный код не делает его исходным кодом.
источник
/etc/
файлы в Unix и т. Д.Наиболее частым вариантом использования генераторов кода, с которыми мне приходилось работать в своей карьере, были генераторы, которые
принял в качестве входных данных некоторое мета-описание высокого уровня для некоторой модели данных или схемы базы данных (может быть, реляционная схема или какая-то схема XML)
и произвел CRUD-код стандартной схемы для классов доступа к данным в качестве выходных данных и, возможно, дополнительных вещей, таких как соответствующие SQL или документация.
Преимущество здесь в том, что из одной строки краткой спецификации ввода вы получаете от 5 до 10 строк отлаживаемого, безопасного с точки зрения типов, безошибочного (предполагается, что вывод генератора кода является зрелым) кода, который в противном случае вам пришлось бы реализовывать и поддерживать вручную. Вы можете себе представить, насколько это уменьшает усилия по обслуживанию и развитию.
Позвольте мне также ответить на ваш первоначальный вопрос
Нет, не генерация исходного кода как таковая, но действительно есть некоторые подводные камни. Как сказано в Pragmatic Programmer , следует избегать использования генератора кода, когда он генерирует код, который трудно понять . В противном случае возросшие усилия по использованию или отладке этого кода могут легко перевесить сэкономленные усилия, если не писать код вручную.
Я также хотел бы добавить, что в большинстве случаев хорошей идеей является физическое отделение сгенерированных частей кода от кода, написанного вручную, таким образом, чтобы повторная генерация не перезаписывала какие-либо изменения вручную. Тем не менее, я также неоднократно сталкивался с ситуацией, когда задача состояла в том, чтобы перенести некоторый код, написанный на старом языке X, на другой, более современный язык Y, с намерением впоследствии перейти на обслуживание на языке Y. Это допустимое использование чехол для одноразовой генерации кода.
источник
Я столкнулся с двумя вариантами использования для сгенерированного (во время сборки и никогда не проверенного) кода:
источник
Сассманн много интересного говорил о таких вещах в своей классической «Структуре и интерпретации компьютерных программ», главным образом о двойственности кода и данных.
Для меня основным применением генерации кода adhoc является использование доступного компилятора для преобразования небольшого предметно-ориентированного языка в то, что я могу связать в своих программах. Думайте BNF, думайте ASN1 (на самом деле, нет, это некрасиво), думайте электронные таблицы словаря данных.
Тривиальные доменные языки могут значительно сэкономить время, и вывод чего-то, что может быть скомпилировано стандартными языковыми инструментами, - это способ создания таких вещей, которые вы бы предпочли отредактировать, нетривиальный взломанный парсер на любом родном языке. писать, или BNF для автоматически сгенерированного?
Выводя текст, который затем подается в какой-то системный компилятор, я получаю всю эту оптимизацию компиляторов и специфичные для системы конфигурации без необходимости думать об этом.
Я эффективно использую язык ввода компилятора как еще одно промежуточное представление, в чем проблема? Текстовые файлы не являются исходным кодом, они могут быть IR для компилятора , и если они выглядят как C или C ++ или Java или что-то еще, кого это волнует?
Теперь, если вам трудно думать, что вы можете отредактировать OUTPUT парсера языка игрушек, что явно разочарует, когда в следующий раз кто-то отредактирует файлы входного языка и перестроит, ответ - не фиксировать автоматически сгенерированный IR в репо. генерируется вашим инструментарием (и избегайте таких людей в вашей группе разработчиков, они, как правило, счастливее работать в маркетинге).
Это не столько недостаток выразительности в наших языках, сколько выражение того, что иногда вы можете получить (или массировать) части спецификации в форму, которую можно автоматически преобразовать в код, и которая, как правило, порождает гораздо меньше ошибки и быть гораздо проще в обслуживании. Если я могу дать нашим сотрудникам по тестированию и настройке электронную таблицу, которую они могут настроить, и инструмент, который они затем запустят, который берет эти данные и выкладывает полный шестнадцатеричный файл для флэш-памяти на моем ECU, тогда это огромная экономия времени, если кто-то переводит вручную последняя настройка в набор констант на языке дня (в комплекте с опечатками).
То же самое с построением моделей в Simulink, а затем генерацией C с RTW и последующей компиляцией с использованием любого инструмента, который имеет смысл, промежуточный C не читается, и что? Высокоуровневому материалу Matlab RTW нужно знать только подмножество C, а компилятор C заботится о деталях платформы. Единственный раз, когда человеку приходится разбираться в сгенерированном C, это когда в скриптах RTW есть ошибка, и такие вещи гораздо легче отлаживать с помощью номинально читаемого IR, чем с помощью только двоичного дерева разбора.
Конечно, вы можете писать такие вещи для вывода байт-кода или даже исполняемого кода, но зачем вам это делать? У нас есть инструменты для преобразования IR в эти вещи.
источник
Прагматичный ответ: является ли генерация кода необходимой и полезной? Предоставляет ли это что-то действительно полезное и необходимое для проприетарной кодовой базы, или кажется, что оно просто создает другой способ работы таким образом, который увеличивает интеллектуальные издержки для неоптимальных результатов?
Если вам нужно задать этот вопрос, и нет четкого ответа, то, вероятно, генерация кода является излишней и просто вносит экзотику и большую интеллектуальную нагрузку на вашу кодовую базу.
Между тем, если вы берете что-то вроде OpenShadingLanguage: https://github.com/imageworks/OpenShadingLanguage
... тогда такие вопросы ставить не нужно, поскольку на них сразу же отвечают впечатляющие результаты.
В таком случае вам не нужно подвергать сомнению существование генератора кода. Если вы работаете в этом типе домена VFX, то ваш немедленный ответ обычно звучит примерно так: «Замолчи и возьми мои деньги!» или «вау, нам тоже нужно сделать что-то подобное».
источник
Нет, генерация промежуточного кода не является анти-паттерном. Ответ на другую часть вашего вопроса, «Зачем это делать?», Является очень широким (и отдельным) вопросом, хотя я все равно приведу некоторые причины.
Исторические последствия отсутствия промежуточного читабельного кода
Давайте возьмем C и C ++ в качестве примеров, поскольку они являются одними из самых известных языков.
Вы должны заметить, что логическая последовательность компиляции кода C выводит не машинный код, а скорее читаемый человеком код сборки. Аналогично, старые компиляторы C ++ раньше физически компилировали код C ++ в код C. В этой цепочке событий вы можете скомпилировать из читаемого человеком кода 1 в читаемый человеком код 2 в читаемый человеком код 3 для машинного кода. "Почему?" Почему нет?
Если промежуточный, читаемый человеком код никогда не генерировался, мы могли бы вообще не иметь C или C ++. Это, безусловно, возможность; люди идут по пути наименьшего сопротивления своим целям, и если какой-то другой язык наберет обороты первым из-за стагнации развития C, C мог бы умереть, пока он был еще молод. Конечно, вы могли бы возразить: «Но тогда, возможно, мы будем использовать какой-то другой язык, и, возможно, это будет лучше». Может быть, а может и хуже будет. Или, может быть, мы все еще будем писать на ассемблере.
Зачем использовать промежуточный человекочитаемый код?
пример
До этого я работал над проектами, в которых нужно было генерировать код на основе данных или информации в каком-то другом документе. Например, один проект имел все свои сетевые сообщения и постоянные данные, определенные в электронной таблице, и инструмент, который будет проходить через электронную таблицу и генерировать много кода на C ++ и Java, который позволит нам работать с этими сообщениями.
Я не говорю, что это был лучший способ настроить этот проект (я не участвовал в его запуске), но это было то, что у нас было, и это были сотни (может быть, даже тысячи, не уверен) структур, объектов и констант которые генерировались; в этот момент, вероятно, уже слишком поздно, чтобы попытаться переделать что-то вроде Rhapsody. Но даже если бы он был переделан во что-то вроде Rhapsody, тогда у нас все равно есть код, сгенерированный из Rhapsody .
Кроме того, наличие всех этих данных в электронной таблице было хорошо с одной стороны: это позволило нам представлять данные способами, которые мы не могли бы иметь, если бы все они были просто в файлах исходного кода.
Пример 2
Когда я немного поработал над созданием компилятора, я использовал инструмент Antlr, чтобы выполнять лексинг и анализ. Я указал грамматику языка, затем использовал инструмент, чтобы выплюнуть тонну кода на C ++ или Java, затем я использовал этот сгенерированный код вместе со своим собственным кодом и включил его в сборку.
Как еще это должно было быть сделано? Возможно, вы могли бы придумать другой путь; Возможно, есть и другие способы. Но для этой работы другие способы были бы не лучше, чем сгенерированный код lex / parse, который у меня был.
источник
То, что вам не хватает, это повторное использование .
У нас есть удивительный инструмент для преобразования текста исходного кода в двоичный, называемый компилятором. Его входные данные четко определены (обычно!), И было проделано много работы, чтобы уточнить, как он выполняет оптимизацию. Если вы действительно хотите использовать компилятор для выполнения некоторых операций, вы хотите использовать существующий компилятор, а не писать свой собственный.
Многие люди изобретают новые языки программирования и пишут свои собственные компиляторы. Почти все без исключения они все делают это, потому что им нравится этот вызов, а не потому, что им нужны функции, которые предоставляет этот язык. Все, что они делают, может быть сделано на другом языке; они просто создают новый язык, потому что им нравятся эти функции. Но чего они не получат, так это хорошо настроенного, быстрого, эффективного, оптимизирующего компилятора. Это даст им что-то, что может превратить текст в двоичный файл, конечно, но это будет не так хорошо, как у всех существующих компиляторов .
Текст - это не просто то, что люди читают и пишут. Компьютеры тоже отлично сочетаются с текстом. Фактически форматы, такие как XML (и другие связанные форматы), успешны, потому что они используют простой текст. Бинарные форматы файлов часто неясны и плохо документированы, и читатель не может легко выяснить, как они работают. XML относительно самодокументируется, поэтому людям проще писать код, который использует файлы в формате XML. И все языки программирования настроены на чтение и запись текстовых файлов.
Итак, предположим, вы хотите добавить какое-то новое средство, чтобы сделать вашу жизнь проще. Возможно, это инструмент макета GUI. Возможно, это интерфейсы сигналов и слотов, которые предоставляет Qt . Возможно, именно так Code Composer Studio от TI позволяет настроить устройство, с которым вы работаете, и вставить нужные библиотеки в сборку. Возможно, он использует словарь данных и автоматически генерирует определения типов и определения глобальных переменных (да, это все еще очень важно во встроенном программном обеспечении). Как бы то ни было, самый эффективный способ использовать ваш существующий компилятор - это создать инструмент, который будет принимать вашу конфигурацию, какой бы она ни была, и автоматически генерировать код на выбранном вами языке.
Его легко разрабатывать и тестировать, потому что вы знаете, что происходит, и можете прочитать исходный код, который он выплевывает. Вам не нужно тратить человеко-годы на создание компилятора, чтобы конкурировать с GCC. Вам не нужно изучать совершенно новый язык или требовать от других людей. Все, что вам нужно сделать, это автоматизировать эту маленькую область, а все остальное остается прежним. Дело сделано.
источник
Немного более прагматичный ответ, сосредоточенный на том, почему, а не на том, что является и не является исходным кодом. Обратите внимание, что генерация исходного кода является частью процесса сборки во всех этих случаях - поэтому сгенерированные файлы не должны попадать в систему контроля версий.
Interoprability / простота
Возьмем основной пример протокола Google Buffers: вы пишете одно описание протокола высокого уровня, которое затем можно использовать для создания реализации на нескольких языках - часто разные части системы пишутся на разных языках.
Реализация / технические причины
Возьмем TypeScript - браузеры не могут его интерпретировать, поэтому в процессе сборки используется JavaScript ( преобразователь кода в код) для генерации JavaScript. Фактически, многие новые или эзотерические скомпилированные языки начинаются с переноса на C, прежде чем они получают правильный компилятор.
Простота использования
Для встроенных проектов (например, IoT), написанных на C и использующих только один двоичный файл (ОСРВ или без ОС), довольно просто сгенерировать массив C с данными, которые должны быть скомпилированы, как если бы это был нормальный исходный код, так как он предназначен для непосредственного их связывания. как ресурсы.
редактировать
Расширение на protobuf: генерация кода позволяет сгенерированным объектам быть первоклассными классами на любом языке. В скомпилированном языке универсальный синтаксический анализатор должен по необходимости возвращать структуру ключ-значение - это означает, что вам не нужно много шаблонного кода, вы пропускаете некоторые проверки во время компиляции (в частности, ключей и типов значений), получаете худшую производительность и нет завершения кода. Представьте себе все те, что
void*
в C или такие огромныеstd::variant
в C ++ (если у вас есть C ++ 17), некоторые языки могут вообще не иметь такой возможности.источник
Это обходной путь для недостаточно выразительного языка программирования. Нет необходимости генерировать код на языке, который содержит адекватное встроенное метапрограммирование.
источник
Генерация исходного кода не всегда является анти-паттерном. Например, я сейчас пишу фреймворк, который по заданной спецификации генерирует код на двух разных языках (Javascript и Java). Фреймворк использует сгенерированный Javascript для записи действий пользователя в браузере и использует код Java в Selenium для фактического выполнения действия, когда фреймворк находится в режиме воспроизведения. Если бы я не использовал генерацию кода, мне пришлось бы вручную убедиться, что оба они всегда синхронизированы, что обременительно и в некотором смысле является логическим дублированием.
Однако если кто-то использует генерацию исходного кода для замены таких функций, как дженерики, то это анти-паттерн.
источник
Может быть, хороший пример, где посреднический код оказался причиной успеха? Я могу предложить вам HTML.
Я считаю, что для HTML было важно быть простым и статичным - это облегчало создание браузеров, позволяло запускать мобильные браузеры на ранней стадии и т. Д. Как показали дальнейшие эксперименты (Java-апплеты, Flash) - более сложные и мощные языки приводят к большему количеству проблем. , Оказывается, что пользователи фактически подвергаются опасности из-за Java-апплетов, и посещение таких веб-сайтов было таким же безопасным, как и попытки взломать игру, загруженную через DC ++. Простой HTML, с другой стороны, достаточно безвреден, чтобы позволить нам проверить любой сайт с разумной уверенностью в безопасности нашего устройства.
Однако HTML был бы далеко не таким, как сейчас, если бы он не был сгенерирован компьютером. Мой ответ даже не появится на этой странице, пока кто-нибудь не переписает его вручную из базы данных в файл HTML. К счастью, вы можете использовать HTML практически на любом языке программирования :)
Можете ли вы представить себе лучший способ отобразить вопрос и все ответы и комментарии для пользователя, чем с помощью HTML в качестве сгенерированного промежуточного кода?
источник
Потому что это быстрее и проще (и менее подвержено ошибкам), чем написание кода вручную, особенно для утомительных, повторяющихся задач. Вы также можете использовать высокоуровневый инструмент для проверки и подтверждения вашего дизайна перед написанием единой строки кода.
Общие случаи использования:
Что касается вашего «почему бы просто не сделать его функцией и напрямую передать ей параметры», обратите внимание, что ни одно из вышеперечисленного не является средой исполнения само по себе. Нет никакого способа связать ваш код с ними.
источник
Иногда ваш язык программирования не имеет необходимых вам средств, что делает невозможным написание функций или макросов для выполнения того, что вы хотите. Или, может быть, вы могли бы делать то, что вы хотите, но код для его написания был бы уродливым. Простой сценарий Python (или аналогичный) может затем сгенерировать требуемый код как часть вашего процесса сборки, который вы затем вводите
#include
в реальный исходный файл.Откуда я это знаю? Потому что это решение, которое я достигал несколько раз при работе с различными системами, совсем недавно SourcePawn. Простой скрипт Python, который анализирует простую строку исходного кода и создает две или три строки сгенерированного кода, намного лучше, чем создание вручную сгенерированного кода, когда у вас получается две дюжины таких строк (создавая все мои cvars).
Демонстрационный / пример исходного кода доступен, если люди этого хотят.
источник
Текстовая форма необходима для удобства потребления людьми. Компьютеры также довольно легко обрабатывают код в текстовом виде. Поэтому сгенерированный код должен быть сгенерирован в форме, которую легче всего генерировать и легче всего использовать на компьютерах, и это очень часто читаемый текст.
И когда вы генерируете код, сам процесс генерации кода часто должен быть отлажен - людьми. Это очень, очень полезно, если сгенерированный код удобочитаем, чтобы люди могли обнаруживать проблемы в процессе генерации кода. Кто-то должен написать код для генерации кода, в конце концов. Это не происходит из воздуха.
источник
Генерация кода, только один раз
Не вся генерация исходного кода - это случай генерации некоторого кода, а затем его никогда не трогать; затем восстановить его из исходного источника, когда он нуждается в обновлении.
Иногда вы генерируете код только один раз, а затем отбрасываете исходный код и продвигаетесь вперед, поддерживая новый источник.
Это иногда происходит при переносе кода с одного языка на другой. В частности, если вы не ожидаете, что позже захотите перенести новые изменения в оригинал (например, старый языковой код не будет поддерживаться или будет фактически завершен (например, в случае некоторых математических функций)).
Одним из распространенных случаев является то, что написание генератора кода для этого может фактически только правильно перевести 90% кода. и затем эти последние 10% должны быть исправлены вручную. Что намного быстрее, чем перевод на 100% вручную.
Такие генераторы кода часто сильно отличаются от генераторов кода, которые
f2c
создают полноязычные переводчики (например, Cython или ). Поскольку цель состоит в том, чтобы один раз сохранить код. Они часто сделаны как 1, чтобы сделать именно то, что они должны. Во многих отношениях это версия следующего уровня использования regex / find-replace для кода порта. «Портирование с помощью инструмента», можно сказать.Генерация кода, всего один раз, например, с сайта.
Близко связано, если вы генерируете код из какого-то источника, к которому вы не хотите обращаться снова. Например, если действия, необходимые для генерации кода, не могут быть повторяемыми, непротиворечивыми или выполнять их дорого. Сейчас я работаю над парой проектов: DataDeps.jl и DataDepsGenerators.jl .
DataDeps.jl помогает пользователям загружать данные (например, стандартные наборы данных ML). Для этого ему нужно то, что мы называем RegistrationBlock. Это некоторый код, указывающий некоторые метаданные, например, откуда загружать файлы, и контрольную сумму, и сообщение, объясняющее пользователю любые термины / кодировки / каков статус лицензирования данных.
Написание этих блоков может быть раздражающим. И эта информация часто доступна (структурированной или неструктурированной) с веб-сайтов, на которых хранятся данные. Таким образом, DataDepsGenerators.jl использует веб-браузер для генерации кода RegistrationBlockCode для некоторых сайтов, на которых размещено много данных.
Это может не генерировать их правильно. Поэтому разработчик, использующий сгенерированный код, может и должен проверить и исправить его. Скорее всего, они хотят убедиться, что он не пропустил информацию о лицензировании, например.
Важно отметить, что пользователям / разработчикам, работающим с DataDeps.jl, не нужно устанавливать или использовать веб-браузер для использования сгенерированного кода RegistrationBlock. (И не нужно загружать и устанавливать веб-скребок, это экономит немало времени. Особенно для запуска CI)
Генерация исходного кода один раз не является антипаттерном. и его обычно нельзя заменить метапрограммированием.
источник
f2c
+cc
), но полученный код не был действительно хорошей отправной точкой для C-версии программы AFAIK.f2c
в тот день)sed
идет долгий путь, но иногда нужно немного больше выразительной силы. Граница между логикой программы и данными часто тонкая. Иногда различие не полезно. JSON - это (/ was) просто код конструктора объекта javascript. В моем примере я также генерирую код конструктора объекта (это данные? Может быть (возможно, нет, потому что иногда у него есть вызовы функций). Лучше ли это рассматривать как код? Да.)Генерация «исходного» кода является признаком недостатка генерируемого языка. Является ли использование инструментов для преодоления этого анти-паттерна? Абсолютно нет - позвольте мне объяснить.
Обычно используется генерация кода, поскольку существует определение более высокого уровня, которое может описать полученный код гораздо менее многословно, чем язык более низкого уровня. Таким образом, генерация кода способствует эффективности и краткости.
Когда я пишу на С ++, я делаю это, потому что это позволяет мне писать код более эффективно, чем с использованием ассемблера или машинного кода. Тем не менее машинный код генерируется компилятором. В начале, c ++ был просто препроцессором, который генерировал C-код. Языки общего назначения отлично подходят для генерации поведения общего назначения.
Таким же образом, используя DSL (предметно-ориентированный язык), можно писать кратко, но, возможно, код ограничен для конкретной задачи. Это облегчит генерацию правильного поведения кода. Помните, что код означает конец и конец . Разработчик ищет эффективный способ генерировать поведение.
В идеале генератор может создавать быстрый код из входных данных, которыми проще манипулировать и понимать. Если это выполняется, то использование генератора не является анти-паттерном . Это анти-модель , как правило , исходит из того , что «чистый» код является «чист», во многом таким же образом дерево рабочего или другой ремесленник может выглядеть при использовании электроинструментов, или использовании ЧПУ для «генерировать» заготовки (думает , что золотое молоток ).
С другой стороны, если источник сгенерированного кода сложнее поддерживать или генерировать код, который недостаточно эффективен, пользователь попадает в ловушку использования неправильных инструментов (иногда из-за того же золотого молотка ).
источник
Генерация исходного кода абсолютно означает, что сгенерированный код является данными. Но это данные первого класса, данные, которыми может манипулировать остальная часть программы.
Два наиболее распространенных типа данных, которые мне известны и которые интегрированы в исходный код, - это графическая информация об окнах (количество и расположение различных элементов управления) и ORM. В обоих случаях интеграция с помощью генерации кода упрощает манипулирование данными, поскольку вам не нужно проходить дополнительные «специальные» шаги для их использования.
При работе с оригинальными компьютерами Mac (1984 г.) определения диалогов и окон создавались с помощью редактора ресурсов, который сохранял данные в двоичном формате. Использовать эти ресурсы в вашем приложении было сложнее, чем было бы, если бы «двоичным форматом» был Паскаль.
Итак, нет, генерация исходного кода не является анти-паттерном, она позволяет сделать часть данных приложения, что упрощает его использование.
источник
Генерация кода - это анти-паттерн, когда он стоит больше, чем достигает. Эта ситуация возникает, когда генерация происходит из A в B, где A - почти тот же язык, что и B, но с некоторыми незначительными расширениями, которые можно сделать, просто кодируя в A с меньшими усилиями, чем все пользовательские инструменты и этапы сборки для A - B. ,
Компромисс является более запретительным по отношению к генерации кода в языках, которые не имеют средств метапрограммирования (структурных макросов) из-за сложностей и неадекватности достижения метапрограммирования посредством организации внешней обработки текста.
Плохой компромисс также может быть связан с количеством использования. Язык A может существенно отличаться от B, но весь проект с его собственным генератором кода использует A только в одном или двух небольших местах, так что общая сложность (маленькие биты A плюс генератор кода A -> B, плюс окружающая стадия сборки) превышает сложность решения, только что выполненного в B.
По сути, если мы берем на себя обязательство генерировать код, нам, вероятно, следует «пойти дальше или пойти домой»: сделать так, чтобы у него была существенная семантика, и использовать его часто, или не беспокоиться.
источник
Я не видел этого ясно сформулированного (я видел, что это затронуто одним или двумя ответами, но это не казалось очень ясным)
Генерация кода (как вы сказали, как будто это данные) не является проблемой - это способ повторно использовать компилятор для вторичной цели.
Редактирование сгенерированного кода является одним из самых коварных, злых, ужасных анти-паттернов, которые вы когда-либо встречали. Не делай это.
В лучшем случае редактирование сгенерированного кода тянет кучу плохого кода в ваш проект (ВЕСЬ набор кода теперь действительно КОД ИСТОЧНИКА - больше не данные). В худшем случае код, загруженный в вашу программу, является сильно избыточным, плохо именуемым мусором, который почти полностью не поддерживается.
Я полагаю, что третья категория - это код, который вы используете один раз (генератор графического интерфейса?), А затем отредактируйте, чтобы помочь вам начать обучение. Это немного из каждого - это МОЖЕТ быть хорошим способом для начала, но ваш генератор GUI будет нацелен на использование генерируемого кода, который не будет хорошим началом для вас, как для программиста. Кроме того, вы можете Соблазн использовать его снова для второго GUI, что означает вытягивание избыточного кода SOURCE в вашу систему.
Если ваш инструментарий достаточно умен, чтобы запретить какие-либо изменения сгенерированного кода, сделайте это. Если нет, я бы назвал это одним из худших анти-паттернов.
источник
Код и данные: информация.
Данные - это информация именно в той форме, которая вам нужна (и ценность). Код также является информацией, но в косвенной или промежуточной форме. По сути, код также является формой данных.
В частности, код - это информация для машин, которая сама по себе освобождает людей от обработки информации.
Разгрузка людей от обработки информации является наиболее важным мотивом. Промежуточные шаги приемлемы, если они облегчают жизнь. Вот почему существуют промежуточные инструменты отображения информации. Как генераторы кода, компиляторы, транспортеры и т. Д.
Допустим, кто-то предлагает вам такую функцию отображения, реализация которой вам неизвестна. Пока функция работает так, как было обещано, вам будет интересно, генерирует ли она исходный код внутри или нет?
источник
Поскольку позже вы укажете, что код - это данные, ваше предложение сводится к «Если что-то может быть сгенерировано, то это не код». Не могли бы вы сказать, что ассемблерный код, сгенерированный компилятором C, не является кодом? Что, если это точно совпадает с кодом сборки, который я пишу от руки? Вы можете пойти туда, если хотите, но я не пойду с вами.
Давайте начнем с определения «кода». Не вдаваясь в технические подробности, довольно хорошим определением для целей этого обсуждения были бы «машинно-управляемые инструкции для выполнения вычислений».
Да, ваше начальное предложение состоит в том, что код не может быть сгенерирован, но я отклоняю это предложение. Если вы согласны с моим определением «кода», тогда не должно быть никаких концептуальных проблем с генерацией кода в целом.
Что ж, это совершенно другой вопрос, касающийся причины создания кода, а не его природы. Вы предлагаете альтернативу, что вместо написания или использования генератора кода, вы пишете функцию, которая вычисляет результат напрямую. Но на каком языке? Прошли те времена, когда кто-то писал непосредственно в машинном коде, и если вы пишете свой код на любом другом языке, то вы зависите от генератора кода в виде компилятора и / или ассемблера для создания программы, которая фактически выполняется.
Почему же тогда вы предпочитаете писать на Java, C, Lisp или что-то еще? Даже ассемблер? Я утверждаю, что, по крайней мере, частично, потому что эти языки предоставляют абстракции для данных и операций, которые облегчают выражение деталей вычислений, которые вы хотите выполнить.
То же самое относится и к большинству генераторов кода более высокого уровня. Прототипными случаями, вероятно, являются сканеры и генераторы парсеров, такие как
lex
иyacc
. Да, вы можете написать сканер и парсер непосредственно на C или на другом языке программирования по вашему выбору (даже необработанный машинный код), а иногда и так. Но для проблемы любой существенной сложности использование высокоуровневого языка специального назначения, такого как lex или yacc, облегчает написание, чтение и обслуживание рукописного кода. Обычно тоже намного меньше.Вы должны также рассмотреть, что именно вы подразумеваете под «генератором кода». Я хотел бы рассмотреть предварительную обработку C и создание шаблонов C ++ как упражнения при генерации кода; Вы возражаете против этого? Если нет, то я думаю, что вам нужно выполнить некоторую умственную гимнастику, чтобы рационализировать принятие этих, но отвергая другие разновидности генерации кода.
Почему? Вы в основном утверждаете, что у вас должна быть универсальная программа, в которую пользователь передает данные, некоторые классифицируются как «инструкции», а другие как «ввод», и которая выполняет вычисления и генерирует больше данных, которые мы называем «выводом». (С определенной точки зрения такую универсальную программу можно назвать «операционной системой».) Но почему вы полагаете, что компилятор должен быть столь же эффективен для оптимизации такой универсальной программы, как и для оптимизации более специализированной? программа? Две программы имеют разные характеристики и разные возможности.
Вы говорите, что как будто наличие универсальной в некоторой степени библиотеки интерфейса обязательно будет хорошей вещью. Возможно, так и будет, но во многих случаях такая библиотека будет большой и трудной для написания и поддержки, а может быть, даже медленной. И если такого зверя на самом деле не существует для решения конкретной проблемы, то кто вы такой, чтобы настаивать на том, чтобы он был создан, когда подход генерации кода может решить проблему намного быстрее и проще?
Я думаю несколько вещей.
Генераторы кода преобразуют код, написанный на одном языке, в код на другом, обычно более низком уровне языка. Вы спрашиваете, почему люди хотят писать программы на нескольких языках, и особенно, почему они могут хотеть смешивать языки субъективно разных уровней.
Но я уже коснулся этого. Один выбирает язык для конкретной задачи, частично основываясь на его ясности и выразительности для этой задачи. Поскольку меньший код в среднем содержит меньше ошибок и его легче обслуживать, существует также и уклон в сторону языков более высокого уровня, по крайней мере, для крупномасштабной работы. Но сложная программа включает в себя много задач, и часто некоторые из них могут быть более эффективно решены на одном языке, тогда как другие более эффективно или более кратко решаются на другом языке. Использование правильного инструмента для работы иногда означает использование генерации кода.
источник
Отвечая на вопрос в контексте вашего комментария:
Компилятор никогда не будет оптимизирован для вашей задачи. Причина этого проста: он оптимизирован для выполнения многих задач. Это универсальный инструмент, используемый многими людьми для множества различных задач. Как только вы узнаете, в чем заключается ваша задача, вы можете подходить к коду с учетом специфики домена, делая компромиссы, которые не могли компиляторы.
В качестве примера я работал над программным обеспечением, в котором аналитику может понадобиться написать некоторый код. Они могли бы написать свой алгоритм на C ++ и добавить все проверки границ и трюки запоминания, от которых они зависят, но для этого нужно много знать о внутренней работе кода. Они скорее написали бы что-нибудь простое, и позвольте мне добавить алгоритм для генерации окончательного кода C ++. Затем я могу сделать экзотические трюки, чтобы максимизировать производительность, такие как статический анализ, который я бы никогда не ожидал от моих аналитиков. Генерация кода позволяет им писать в предметной области, что позволяет им вывести продукт на улицу проще, чем любой универсальный инструмент.
Я также сделал прямо противоположное. У меня есть еще одна часть работы, у которой был мандат «нет генерации кода». Мы все еще хотели упростить жизнь тем, кто использует программное обеспечение, поэтому мы использовали огромное количество шаблонов метапрограммирования, чтобы компилятор генерировал код на лету. Таким образом, мне нужен был только язык C ++ общего назначения, чтобы выполнять свою работу.
Тем не менее, есть подвох. Было чрезвычайно трудно гарантировать, что ошибки были читаемы. Если вы когда-либо использовали шаблонный метапрограммированный код ранее, вы знаете, что одна невинная ошибка может привести к ошибке, которая берет 100 строк непонятных имен классов и аргументов шаблона, чтобы понять, что пошло не так. Этот эффект был настолько выражен, что рекомендуемый процесс отладки для синтаксических ошибок был «прокручивать журнал ошибок до тех пор, пока в первый раз не обнаружится ошибка в одном из ваших собственных файлов. сделал не так. "
Если бы мы использовали генерацию кода, мы могли бы иметь гораздо более мощные возможности обработки ошибок с ошибками, читаемыми человеком. Такова жизнь.
источник
Есть несколько разных способов использования генерации кода. Их можно разделить на три основные группы:
Я предполагаю, что вы говорите о третьем типе сгенерированного кода, так как это наиболее спорная форма. В первых двух формах сгенерированный код является промежуточным этапом, который очень четко отделен от исходного кода. Но в третьей форме нет формального разделения между исходным кодом и сгенерированным кодом, за исключением того, что сгенерированный код, вероятно, имеет комментарий, который говорит: «не редактируйте этот код». Это по-прежнему открывает риск для разработчиков, редактирующих сгенерированный код, что было бы действительно ужасно. С точки зрения компилятора сгенерированный код является исходным кодом.
Тем не менее, такие формы сгенерированного кода могут быть действительно полезны в статически типизированном языке. Например, при интеграции с объектами ORM действительно полезно иметь строго типизированные оболочки для таблиц базы данных. Конечно, вы можете динамически управлять интеграцией во время выполнения, но вы потеряете безопасность типов и поддержку инструментов (завершение кода). Основным преимуществом языка статических типов является поддержка системы типов в типе письма, а не только во время выполнения. (И наоборот, этот тип генерации кода не очень распространен в динамически типизированных языках, поскольку в таком языке он не дает никакой выгоды по сравнению с преобразованиями во время выполнения.)
Поскольку безопасность типов и завершение кода - это функции, которые вам нужны во время компиляции (и при написании кода в IDE), но обычные функции выполняются только во время выполнения.
Хотя может быть и золотая середина: F # поддерживает концепцию провайдеров типов, которые в основном представляют собой строго типизированные интерфейсы, генерируемые программно во время компиляции. Эта концепция может заменить многие виды использования генерации кода и обеспечить более четкое разделение задач.
источник
Наборы инструкций процессора принципиально необходимы , но языки программирования могут быть декларативными . Запуск программы, написанной на декларативном языке, неизбежно требует некоторого типа генерации кода. Как упоминалось в этом и других ответах , основной причиной генерации исходного кода на понятном человеку языке является использование преимуществ сложной оптимизации, выполняемой компиляторами.
источник
Вы неправильно поняли. Следует читать
Если что-то может быть передано в генератор для интерпретируемых , то это код, а не данные.
Это исходный формат для этой стадии компиляции, а формат приемника все еще является кодом.
источник
gcc -fverbose-asm -O -S
, не является исходным кодом (и не является единственным или главным образом данными), даже если это некоторая текстовая форма, всегда передаваемая в GNUas
и иногда читаемая людьми.