Чи генерація вихідного коду є антидіаграмою?


118

Якщо щось можна створити, то ця річ - це дані, а не код.

Враховуючи це, чи не вся ця ідея створення вихідного коду є непорозумінням? Тобто, якщо для чогось є генератор коду, то чому б не зробити це чимось належною функцією, яка може приймати необхідні параметри і робити правильні дії, які б зробив код "сгенерований"?

Якщо це робиться з міркувань продуктивності, то це звучить як недолік компілятора.

Якщо це робиться для з'єднання двох мов, то це звучить як брак бібліотеки інтерфейсів.

Я чогось тут пропускаю?

Я знаю, що код також є даними. Що я не розумію, чому генерувати вихідний код ? Чому б не перетворити його на функцію, яка може приймати параметри і діяти на них?


11
Термін, пов'язаний з генерацією коду, - метапрограмування
UselesssCat

4
en.wikipedia.org/wiki/Code_as_data , Lisp, FP, сценарії, метапрограмування, фон Нойман / модифікована Гарвардська архітектура тощо. Це було охоплено рекламною нудотою . tl; dr. розрізнення "вихідний код" проти "вихідний код", "код" проти "даних" і т.д. призначені для спрощення речей. Вони ніколи не повинні бути догматичними .
vaxquis

9
@Utku, кращі причини створення коду часто пов'язані з бажанням надати опис більш високого рівня, ніж може виражати ваша поточна мова . Незалежно від того, компілятор може чи не може створити ефективний код, це насправді не має нічого спільного. Розглянемо генератори парсера - лексери, згенеровані flexабо створені аналізатором, bisonмайже напевно будуть більш передбачуваними, правильнішими та часто швидшими для виконання, ніж еквіваленти, написані вручну на C; і побудований з набагато меншого коду (таким чином, також менше роботи для обслуговування).
Чарльз Даффі

1
Можливо, ви походять з мови, яка не має багатьох функціональних елементів, але в багатьох мовах функції є першокласними - ви можете передавати їх навколо, тому в тих типах мов код є даними, і ви можете ставитися до нього просто так.
Рестіосон

1
@Restioson у коді функціональної мови не є даними. Функції першого класу означають саме це: Функції - це дані. І не обов'язково особливо хороші дані: ви не можете обов'язково їх просто мутувати (наприклад, мутувати всі додавання в межах функцій на віднімання). Код - це дані гомоїконічними мовами. (Більшість гомоніконічних мов мають функції першого класу. Але зворотне не відповідає дійсності.)
Ліндон Уайт

Відповіді:


149

Чи генерація вихідного коду є антитілом?

Технічно, якщо ми генеруємо код, він не є джерелом, навіть якщо це текст, який читає людина. Вихідний код - це оригінальний код, породжений людським чи іншим справжнім інтелектом, який не перекладається механічно і не одразу відтворюється з (справжнього) джерела (прямо чи опосередковано).

Якщо щось можна генерувати, то ця річ - це дані, а не код.

Я б сказав, що все одно це дані . Навіть вихідний код. Особливо вихідний код! Вихідний код - це лише дані мовою, призначені для виконання завдань програмування. Ці дані слід перекладати, інтерпретувати, збирати, генерувати за потребою в інші форми - дані - деякі з яких можуть бути виконаними.

Процесор виконує інструкції з пам'яті. Та сама пам'ять, яка використовується для даних. Перед тим, як процесор виконує вказівки, програма завантажується в пам'ять як дані .

Отже, все - це дані , навіть код .

Враховуючи, що [згенерований код - це дані], чи не вся ця ідея створення коду є непорозумінням?

Цілком чудово мати кілька етапів компіляції, одним з яких може бути проміжне генерування коду у вигляді тексту.

Тобто, якщо для чогось є генератор коду, то чому б не зробити це чимось належною функцією, яка може приймати необхідні параметри і робити правильні дії, які б зробив код "сгенерований"?

Це один спосіб, але є й інші.


Результатом генерації коду є текст, який призначений для використання людиною.

Не всі текстові форми призначені для споживання людиною. Зокрема, згенерований код (як текст) зазвичай призначений для споживання компілятором, а не споживанням людиною.


Вихідний код вважається оригінальним: головний - що ми редагуємо та розробляємо; що ми архівуємо за допомогою контролю вихідного коду. Згенерований код, навіть коли текст, прочитаний людиною, зазвичай відновлюється з вихідного вихідного коду . Згенерований код, взагалі кажучи, не повинен перебувати під контролем джерела, оскільки він відновлюється під час збирання.


1
Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
maple_shaft

65

Практичні міркування

Гаразд, я знаю, що код також є даними. Що я не розумію, чому генерувати вихідний код?

З цієї редакції, я припускаю, що ви запитуєте на досить практичному рівні, а не на теоретичній інформатиці.

Класична причина генерування вихідного коду в статичних мовах, таких як Java, полягала в тому, що подібні мови просто не надходили з простими у використанні мовними інструментами, щоб робити дуже динамічні речі. Наприклад, ще в початкові дні Java просто неможливо було легко створити клас з динамічним іменем (узгодження імені таблиці з БД) та динамічними методами (відповідні атрибути цієї таблиці) з динамічними типами даних (відповідність типи зазначених ознак). Тим більше, що Java ставить цілу велику важливість, найефективніше, гарантії на те, що зможеш під час компіляції вловлювати помилки типу.

Так, у такому налаштуванні програміст може створювати лише код Java та записувати багато рядків коду вручну. Часто програміст виявляє, що кожного разу, коли таблиця змінюється, йому доводиться повертатися назад і змінювати код на відповідність; і якщо він це забуде, трапляються погані речі. Отже, програміст дістанеться до того, коли він запише деякі інструменти, які роблять це для нього. А отже, починається дорога до все розумнішого генерації коду.

(Так, ви можете генерувати байтовий код на льоту, але програмування такого на Java не буде чимось випадковим програмістом, який би робив просто між тим, як записати кілька рядків доменного коду.)

Порівняйте це з дуже динамічними мовами, наприклад, Ruby, яку я б вважав антитезою до Java здебільшого (зауважте, що я це говорю, не оцінюючи жодного підходу; вони просто різні). Тут на 100% нормально і стандартно динамічно генерувати класи, методи і т.д. під час виконання, а головне, програміст може це робити тривіально правильно в коді, не переходячи на "мета" рівень. Так, такі речі, як Ruby on Rails, приходять з генерацією коду, але ми виявили, що в основному ми використовуємо це як своєрідний вдосконалений «режим підручника» для нових програмістів, але через деякий час він стає зайвим (так як код так мало написати в тій екосистемі, що коли ти знаєш, що ти робиш, написання вручну стає швидше, ніж очищення створеного коду).

Це лише два практичні приклади з "реального світу". Тоді у вас є мови на зразок LISP, де код - це дані, буквально. З іншого боку, у складених мовах (без двигуна виконання, як-от Java чи Ruby) немає (або було, я не в курсі сучасних функцій C ++ ...) просто немає концепції визначення назв класів або методів під час виконання, тому генерація коду процес збирання є інструментом вибору для більшості речей (інші більш конкретні приклади C / C ++ - такі речі, як flex, yacc тощо).


1
Я думаю, що це краще, ніж відповіді, на які більше голосів. Зокрема, згаданий приклад з програмуванням Java та програмою баз даних робить набагато кращу роботу щодо вирішення того, чому використовується генерація коду та є дійсним інструментом.
Panzercrisis

Чи можливо сьогодні в Java створити динамічні таблиці з БД? Або лише за допомогою ORM?
Номенон

"(чи було, я не в курсі сучасних функцій C ++ ...)" напевно, це можливо в C ++ вже більше двох десятиліть завдяки функціональним вказівникам? Я не перевіряв його, але я впевнений, що можливо, можливо, виділити масив char, заповнити його машинним кодом, а потім передати покажчик на перший елемент на покажчик функції, а потім запустити його? (Припустимо, що на цільовій платформі немає жодних заходів безпеки, щоб перешкодити вам робити це, що могло б зробити.)
Pharap

1
"виділити масив char, заповнити його машинним кодом, а потім передати покажчик на перший елемент на покажчик функції, а потім запустити його?" Крім не визначеної поведінки, це C ++ еквівалент "генерувати байтовий код на льоту". Він потрапляє до тієї ж категорії, що "не вважається звичайними програмістами"
Калет

1
@Pharap, "напевно, це можливо в С ++ вже більше двох десятиліть" ... Мені довелося трохи посміятися; пройшло приблизно два десятиліття з моменту останнього кодування C ++. :) Але моє речення про С ++ все одно було сформульовано погано. Я це трохи змінив, зараз має бути зрозуміліше, що я мав на увазі.
AnoE

44

навіщо генерувати код?

Тому що програмування перфокартами (або альт-кодами в блокноті ) - це біль.

Якщо це робиться з міркувань продуктивності, то це звучить як недолік компілятора.

Правда. Я не дбаю про продуктивність, якщо мене не змусять.

Якщо це робиться для з'єднання двох мов, то це звучить як брак бібліотеки інтерфейсів.

Хм, ні поняття, про що ти говориш.

Подивіться, це так: Створений і збережений вихідний код - це завжди і назавжди біль у задці. Він існує лише з однієї причини. Хтось хоче працювати на одній мові, а хтось наполягає на роботі на іншій, і ніхто не може потрудитися розібратися, як взаємодіяти між ними, щоб один з них з'ясував, як перетворити свою улюблену мову на нав'язувану мову, щоб вони могли робити що вони хочуть.

Що добре, поки мені не доведеться його підтримувати. У цей момент ви можете всі померти.

Це анти візерунок? Зітхайте, ні. Багато мов навіть не існувало, якби ми не були готові попрощатися з недоліками попередніх мов, а генерування коду старих мов - це кількість нових мов.

Це база коду, яка залишилася в напівконвертованому печворку Франкенштейна, який я не витримую. Створений код - недоторканий код. Я ненавиджу дивитися на недоторканий код. Але люди продовжують перевіряти це. ЧОМУ? Ви також можете перевірити у виконаному файлі.

Ну а тепер я проходжу. Моя думка, ми всі "генеруємо код". Це коли ти ставишся до генерованого коду, як до вихідного коду, мене зводить з розуму. Тільки тому, що схоже, що вихідний код не робить його вихідним кодом.


41
Якщо ви їх генеруєте, це не код ДЖЕРЕЛА. Це проміжний код. Зараз я буду плакати.
candied_orange

65
АРГ !!! Не має значення, як це виглядає !!! Текст, двійковий, ДНК, якщо це не ДЖЕРЕЛ, це не те, до чого слід торкатися, вносячи зміни. Це не є ділом, якщо мій процес компіляції має 42 проміжні мови, які він проходить. Перестаньте їх торкатися. Перестаньте перевіряти їх. Внесіть зміни до джерела.
candied_orange

24
XML - це текст, і він просто не призначений для споживання людиною. :-)
Нік Кейлі

38
@utku: "Якщо щось не призначене для споживання людиною, це не повинно бути текстом": Я повністю не згоден. Кілька зустрічних прикладів у верхній частині моєї голови: протокол HTTP, кодування MIME, файли PEM - майже все, що використовує base64 в будь-якому місці. Є багато причин кодувати дані в 7-бітовий безпечний потік, навіть якщо жодна людина ніколи не бачить їх. Не кажучи вже про набагато більше простору речей , які зазвичай людина ніколи не повинен взаємодіяти з, але що вони можуть захотіти іноді: лог - файли, /etc/файли на Unix і т.д.
Daniel Pryden

12
Я не думаю, що "програмування перфокартами" означає те, що ви думаєте, що це означає. Я був там, я це робив, і так, це був біль; але він не має зв'язку з "створеним кодом". Колода перфокарт - це лише інший вид файлів - як файл на диску, або файл на стрічці, або файл на SD-картці. Ще в той день ми записували б дані в колоди карт і читали з них дані. Отже, якщо причина, по якій ми генеруємо код, полягає в тому, що програмування перфокартами - це біль, то це означає, що програмування з будь-яким типом зберігання даних - це біль.
Соломон повільно

41

чому генерувати вихідний код

Найчастішим випадком використання генераторів коду, з яким мені довелося працювати у своїй кар’єрі, були генератори, які

  • взяв якийсь метаопис високого рівня для якоїсь моделі даних або схеми бази даних як вхідний (можливо, реляційна схема або якась схема XML)

  • і створив код CRUD на плиті котла для класів доступу до даних як вихід, а може бути і додаткові речі, такі як відповідні SQL або документація.

Перевага тут полягає в тому, що з одного рядка короткої специфікації введення ви отримуєте від 5 до 10 рядків налагоджуваного, безпечного для типу, без помилок (якщо вважати, що вихід генераторів коду є зрілим) код, який інакше вам довелося реалізовувати та підтримувати вручну. Ви можете собі уявити, наскільки це зменшує зусилля щодо обслуговування та еволюції.

Дозвольте мені також відповісти на ваше початкове запитання

Чи є генерація вихідного коду антитіл

Ні, не генерація вихідного коду сама по собі, але справді є деякі підводні камені. Як зазначено в «Прагматичному програмісті» , слід уникати використання генератора коду, коли він створює код, який важко зрозуміти . В іншому випадку, посилені зусилля щодо використання або налагодження цього коду можуть легко перевершити зусилля, збережені, не записуючи код вручну.

Я також хотів би додати, що найчастіше корисно фізично відокремити згенеровані частини коду від написаного вручну коду таким чином, щоб повторне покоління не заміняло будь-яких змін вручну. Однак я також неодноразово займався ситуацією, коли завданням було перенести якийсь код, написаний старою мовою X, на іншу, більш сучасну мову Y, з наміром потім підтримувати мову Y. Це правильне використання справа для одноразового генерації коду.


Я згоден з цією відповіддю. Використовуючи щось на зразок Torque для Java, я можу робити автоматичне створення вихідних файлів java, при цьому поля відповідають базі даних sql. Це робить грубі операції набагато легшими. Основна перевага - безпека типу, включаючи лише можливість посилатися на поля, які існують у базі даних (дякую автозаповнення).
MTilsted

Так, для мов статичного типу це важлива частина: ви можете переконатися, що ваш рукописний код насправді підходить до створеного.
Paŭlo Ebermann

"перенести якийсь код, написаний старою мовою" - навіть тоді одноразове створення коду може бути великим болем. Наприклад, після деяких ручних змін ви виявляєте помилку в генераторі та потребуєте повторної генерації після виправлення. На щастя, git або подібні зазвичай можуть полегшити біль.
maaartinus

13

навіщо генерувати вихідний код?

У мене виникли два випадки використання для генерованого (під час збирання та ніколи не зареєстрованого) коду:

  1. Автоматично генерувати кодовий код, такий як getters / setters, toString, equals і hashCode з мови, створеної для вказівки таких речей (наприклад, проект lombok для Java)
  2. Автоматично генерувати класи типу DTO з деяких специфікацій інтерфейсу (REST, SOAP, будь-який інший), щоб потім використовуватись у головному коді. Це схоже на вашу проблему з мостовим мостом, але в кінцевому підсумку стає більш чистим і простим, з кращим керуванням типу, ніж намаганням реалізувати те саме, що не створює класи.

15
Сильно повторюваний код невиразними мовами. Наприклад, мені довелося написати код, який необхідний зробив те саме на багатьох подібних, але не однакових структурах даних. Це , ймовірно , могли б зробити що - щось на зразок шаблону C ++ (агов НЕ , що генерація коду?). Але я використовував C. Генерація коду врятувало мене, коли я писав багато майже однакового коду.
Нік Кейлі

1
@NickKeighley Можливо, ваша ланцюжок інструментів не дозволяла вам використовувати іншу більш підходящу мову?
Вілсон

7
Зазвичай ви не можете вибрати та вибрати мову своєї реалізації. Проект був на С, це не було варіантом.
Нік Кейлі

1
@ Уілсон, що більш виразні мови часто використовують генерацію коду (наприклад, макроси lisp, рубін на рейках), вони просто не вимагають, щоб тим часом зберігатись як текст.
Піт Кіркхем

4
Так, генерація коду - це по суті метапрограмування. Такі мови, як Ruby, дозволяють здійснювати метапрограмування самою мовою, але C - це не так, вам доведеться використовувати замість цього генерацію коду.
Шон Бертон

13

Суссману було цікаво сказати про такі речі у своїй класичній «Структурі та інтерпретації комп’ютерних програм», головним чином про подвійність кодових даних.

Для мене головне використання генерації коду adhoc - це використання наявного компілятора для перетворення невеликої мови, визначеної для домену, у те, що я можу пов’язати у своїх програмах. Подумайте про BNF, подумайте, ASN1 (Насправді, не варто, це некрасиво), подумайте про електронні таблиці словника даних.

Тривіальні мови, що стосуються домену, можуть значно заощадити час, і виведення чогось, що можна скласти за допомогою стандартних мовних інструментів, - це шлях, коли потрібно створювати такі речі, які, скоріше, редагуйте, нетривіальний ручний парсер на будь-якій рідній мові. написання, або BNF для автоматично створеного?

Виводячи текст, який потім подається до якогось компілятора системи, я отримую всю оптимізацію компіляторів та конфігурацію системи, не замислюючись про це.

Я ефективно використовую мову введення компілятора як просто чергове проміжне представлення, в чому проблема? Текстові файли по суті не є вихідним кодом, вони можуть бути ІК для компілятора , і якщо вони трапляються схожими на C або C ++ або Java чи що завгодно, кого це цікавить?

Тепер, якщо вам важко думати, ви можете відредагувати вихідний синтаксичний аналізатор іграшки, що явно розчарує наступного разу, коли хтось редагує вхідні файли мови та перестроїть, відповідь полягає в тому, щоб не зафіксувати автоматично створений ІР-репортаж на репо, майте це створений вашим інструментальним ланцюжком (І уникайте таких людей у ​​вашій групі розробників, вони зазвичай щасливіші, що працюють у маркетингу).

Це не стільки невдача виразності в наших мовах, скільки вираження того факту, що іноді ви можете отримати (або помасажувати) частини специфікації у формі, яку можна автоматично перетворити в код, і якої зазвичай буде набагато менше помилок і бути набагато простішим в обслуговуванні. Якщо я можу дати нашим хлопцям для тестування та конфігурації електронну таблицю, вони можуть налаштувати та інструмент, який вони потім запускають, який забирає ці дані та випиляє повний шістнадцятковий файл для спалаху на моєму ECU, то це величезний економія часу на те, щоб хтось переклав вручну остання настройка на набір констант мовою дня (у комплекті з друкарськими помилками).

Те саме, що побудувати моделі в Simulink, а потім генерувати C за допомогою RTW, потім компілювати для націлювання будь-яким інструментом, який має сенс, проміжний C не читається, і що? На високому рівні Matlab RTW потрібно лише знати підмножину C, а компілятор C піклується про деталі платформи. Єдиний час, коли людині доводиться перебирати сформований C, - це коли в сценаріях RTW з'являється помилка, і подібні речі набагато простіше відлагодити з номінально зрозумілим людським ІЧ, а потім лише з двійковим деревом розбору.

Звичайно, ви можете писати такі речі, щоб виводити байт-код або навіть виконуваний код, але навіщо це робити? Ми отримали інструменти для перетворення ІЧ-сигналу в ці речі.


Це добре, але я додам, що при визначенні того, який ІР використовувати, можна використовувати компроміс: використання C як ІЧ робить деякі речі простішими, а інші складніше, порівняно з, скажімо, мовою складання x86. Вибір є ще більш значущим при виборі між, скажімо, мовним кодом Java та байт-кодом Java, оскільки існує ще багато операцій, які існують лише на тій чи іншій мові.
Даніель Приден

2
Але мова монтажу X86 робить поганий ІЧ при націлюванні на ядро ​​ARM або PPC! Всі речі є компромісом в галузі техніки, тому вони називають це "Інжиніринг". Можна сподіватися, що можливості байт-коду Java були суворим набором можливостей мови Java, і що це взагалі вірно, коли ви наближаєтесь до металу незалежно від ланцюжка інструментів і куди вводите ІЧ.
Ден Міллс

О, я цілком погоджуюся: мій коментар був у відповідь на ваш остаточний параметр, чому ви коли-небудь виводите байт-код або якусь річ нижчого рівня - іноді вам потрібен нижчий рівень. (Спеціально для Java існує багато корисних речей, які ви можете зробити з байт-кодом, який ви не можете зробити на самій мові Java.)
Daniel Pryden

2
Я не погоджуюся, але використання ІЧ-ближчого до металу коштує не тільки в зменшеній загальній здатності, але й у тому, що ви, як правило, відповідальні за більшу справжню оптимізацію низького рівня. Той факт, що ми загалом думаємо сьогодні з точки зору оптимізації вибору алгоритму, а не впровадження, - це відображення того, наскільки далеко дійшли компілятори. Іноді в цих речах вам доведеться дійсно наблизитися до металу, але подумайте двічі, перш ніж викидати компілятори можливість оптимізації за допомогою ІЧ занадто низького рівня.
Ден Міллс

1
"вони, як правило, щасливіші, що працюють в маркетингу" Кетті, але смішні.
dmckee

13

Прагматична відповідь: чи необхідне та корисне створення коду? Чи надає це щось, що є справді дуже корисним і потрібним для фірмової бази коду, чи здається, що це просто створює інший спосіб робити так, щоб сприяти більш інтелектуальним накладним витратам для неоптимальних результатів?

Гаразд, я знаю, що код також є даними. Що я не розумію, чому генерувати код? Чому б не перетворити його на функцію, яка може приймати параметри і діяти на них?

Якщо вам доведеться задати це питання, і немає чіткої відповіді, то, ймовірно, генерація коду зайва і просто сприяє екзотиці та великій кількості інтелектуальних витрат до вашої бази даних.

Тим часом, якщо ви берете щось на кшталт OpenShadingLanguage: https://github.com/imageworks/OpenShadingLanguage

... тоді таких питань не потрібно ставити, оскільки на них негайно відповідають вражаючі результати.

OSL використовує рамку компілятора LLVM для перекладу шейдерних мереж у машинний код на ходу (саме вчасно, або "JIT"), а в процесі сильно оптимізує шейдери та мережі з повним знанням параметрів шейдера та інших значень часу виконання, які не змогли були відомі, коли шейдери складалися з вихідного коду. Як результат, ми бачимо, що наші мережі затінення OSL виконують на 25% швидше, ніж еквівалентні шейдери, виготовлені в C! (Ось так працювали наші старі шейдери в нашому рендері.)

У такому випадку вам не потрібно ставити під сумнів існування генератора коду. Якщо ви працюєте в даному типі домену VFX, то ваш негайний відповідь, як правило, більше на лінії "заткнись і візьми мої гроші!" або, "ух, нам також потрібно зробити щось подібне".


перевести шейдерні мережі в машинний код . Це звучить як компілятор, а не генератор коду, ні?
Утку

2
По суті, вона займає вузлову мережу, яку користувач з'єднує та генерує посередницький код, який компілюється JIT LLVM. Відмінність між компілятором і генератором коду є нечітким. Чи більше ви думали про рядки функцій генерації коду на таких мовах, як шаблони в C ++ або в препроцесорі C?

Я думав про будь-який генератор, який виводить вихідний код.
Утку

Я бачу, де продукція все ще для споживання людиною я припускаю. OpenSL також генерує посередницький вихідний код, але це код низького рівня, близький до збірки для споживання LLVM. Зазвичай це не код, який слід підтримувати (натомість програмісти підтримують вузли, які використовуються для генерування коду). Більшу частину часу я вважаю, що ці типи генераторів коду швидше піддаються зловживанню, ніж достатньо корисним для виправдання їх вартості, особливо якщо вам доведеться постійно регенерувати код у рамках свого процесу збирання. Іноді вони все ще мають справжнє місце, хоча вирішити недоліки ...

... мови, що доступна під час використання для певного домену. QT має один із тих спірних із його компілятором мета-об'єктів (MOC). MOC зменшує плиту котла, як правило, потрібно надати властивості та відбиття, сигнали та прорізи тощо. В C ++, але не в такій мірі, щоб чітко виправдати її існування. Я часто думаю, що QT міг би бути кращим без громіздкого тягаря коду MOC.

8

Ні, генерування проміжного коду не є антитілом. Відповідь на іншу частину вашого питання "Чому це робити?" - дуже широке (і окреме) питання, хоча я все-таки наведу деякі причини.

Історичні наслідки ніколи не мали проміжного для людини коду, що читається

Візьмемо приклади C і C ++, оскільки вони є одними з найвідоміших мов.

Слід зауважити, що логічна обробка компіляції коду С видає не машинний код, а швидше читаний людиною код складання. Так само старі компілятори C ++, які використовувались для фізичного складання коду C ++ у код C. У цьому ланцюжку подій ви можете скласти з читаного людиною коду 1 до людського читаного коду 2 до людського читаного коду 3 до машинного коду. "Чому?" Чому ні?

Якщо проміжний, читабельний для людини код ніколи не генерувався, ми можемо взагалі не мати C або C ++. Це, безумовно, можливість; люди йдуть на шлях найменшого опору до своїх цілей, і якби якась інша мова спочатку здобула пару через застій розвитку С, С могла б померти, будучи ще молодою. Звичайно, ви можете заперечити "Але тоді, можливо, ми б використовували якусь іншу мову, і, можливо, буде краще". Можливо, а може, було б і гірше. А може, ми все ще писатимемо в зборах.

Навіщо використовувати проміжний, зрозумілий людині код?

  1. Іноді потрібен проміжний код, щоб ви могли змінити його до наступного кроку в побудові. Я визнаю, цей пункт є найслабшим.
  2. Іноді це тому, що оригінальна робота взагалі не була виконана будь-якою читаною людиною мовою, а не інструментом моделювання GUI.
  3. Іноді вам потрібно зробити щось дуже повторюване, і мова не повинна задовольняти те, що ви робите, тому що це така ніша або така складна річ, що у неї немає діла, що збільшує складність або граматику мови програмування просто для того, щоб вмістити її. ви.
  4. Іноді вам потрібно зробити щось дуже повторюване, і немає жодного можливого способу ввести загальну мову в мову; або вона не може бути представлена ​​або суперечить граматиці мови.
  5. Однією з цілей комп’ютерів є зменшення зусиль людини, а іноді код, який навряд чи коли-небудь повториться (мала ймовірність технічного обслуговування), може мати мета-код, записаний для генерування вашого більш тривалого коду в десяту частину часу; якщо я можу зробити це в протягом 1 дня замість 2 -х тижнів , і це , ймовірно, не буде підтримуватися постійно, то я краще генерувати його - і на випадок, якщо хто - то через 5 років роздратований , бо вони на насправді дійсно потрібно підтримувати його, то вони можуть витратити 2 тижні, виписавши його повністю, якщо хочуть, або роздратуються на 1 тиждень підтримки незручного коду (але ми все ще на 1 тиждень попереду в цьому пункті), і ось якщо це обслуговування потрібно зробити взагалі .
  6. Я впевнений, що є більше причин, яких я не помічаю.

Приклад

Я раніше працював над проектами, де код повинен формуватися на основі даних або інформації в якомусь іншому документі. Наприклад, один проект мав усі свої мережеві повідомлення та постійні дані, визначені в електронній таблиці та інструмент, який би проходив через електронну таблицю та генерував багато C ++ та Java-коду, який дозволив нам працювати з цими повідомленнями.

Я не кажу, що це був найкращий спосіб налагодити цей проект (я не був частиною його запуску), але це було те, що ми мали, і це були сотні (можливо, навіть тисячі, не впевнені) структур, об'єктів і констант які породжувались; в цей момент, мабуть, пізно спробувати переробити це в щось на зразок Рапсодії. Але навіть якби це було перероблено на щось на зразок Рапсодії, ми все одно маємо код, сформований із Рапсодії .

Крім того, мати всі ці дані в електронній таблиці було добре одним способом: це дозволило нам представляти дані способами, яких ми не могли мати, якби вони були лише у файлах вихідного коду.

Приклад 2

Коли я робив якусь роботу в побудові компілятора, я використовував інструмент Antlr, щоб зробити свій лексинг та розбір. Я вказав мовну граматику, потім застосував цей інструмент, щоб виплюнути тону коду або на C ++, або на Java, потім використав цей генерований код поряд із моїм власним кодом і включив його у збірку.

Як ще треба було це зробити? Можливо, ви могли б придумати інший спосіб; ймовірно, є й інші способи. Але для цієї роботи інші способи були б не кращими за створений у мене лекс / розбір коду.


Ive використовував проміжний код як своєрідний формат файлу та відладку відстеження, коли обидві системи були несумісні, але мали стабільний api якийсь вид, дуже езотеричним сценарієм. Не мав на увазі читати вручну, але міг би бути таким же чином, як і XML. Але це більш часто, ніж ви думаєте, після того, як усі веб-сторінки працюють на цьому шляху, як хтось зазначив.
joojaa

7

Те, що вам не вистачає, - повторне використання .

У нас є дивовижний інструмент для перетворення тексту вихідного коду у двійковий, який називається компілятором. Її вклади чітко визначені (як правило!), І було проведено багато роботи, щоб уточнити, як відбувається оптимізація. Якщо ви дійсно хочете використовувати компілятор для виконання деяких операцій, ви хочете використовувати існуючий компілятор, а не писати свій власний.

Багато людей вигадують нові мови програмування та пишуть власні компілятори. Досить багато без винятку, всі вони роблять це, тому що їм подобається виклик, а не тому, що їм потрібні функції, які надає ця мова. Все, що вони роблять, можна зробити іншою мовою; вони просто створюють нову мову, тому що їм подобаються ці функції. Хоча це не отримає, це добре налаштований, швидкий, ефективний, оптимізуючий компілятор. Це отримає від них щось, що може перетворити текст у двійкове, але це буде не так добре, як усі існуючі компілятори .

Текст - це не просто те, що люди читають і пишуть. Комп'ютери ідеально вдома також і з текстом. Насправді такі формати, як XML (та інші супутні формати), є успішними, оскільки використовують звичайний текст. Формати бінарних файлів часто незрозумілі та слабо документовані, і читач не може легко дізнатися, як вони працюють. XML є відносно самодокументованим, що полегшує людям запис коду, який використовує файли у форматі XML. І всі мови програмування налаштовані на читання та запис текстових файлів.

Отже, припустимо, ви хочете додати нову послугу, щоб полегшити своє життя. Можливо, це інструмент компонування GUI. Можливо, це інтерфейси сигналів і слотів, які надає Qt . Можливо, саме TI's Code Composer Studio дозволяє налаштувати пристрій, з яким ви працюєте, і втягнути потрібні бібліотеки в збірку. Можливо, це потрібен словник даних і автоматично генерує typedefs та визначення глобальних змінних (так, це все ще дуже важливо для вбудованого програмного забезпечення). Як би там не було, найефективнішим способом використання існуючого компілятора є створення інструменту, який візьме вашу конфігурацію будь-що є і автоматично виробляє код на обраній вами мові.

Це легко розробити і легко перевірити, тому що ви знаєте, що відбувається, і ви можете прочитати вихідний код, який він виплює. Вам не потрібно витрачати людино-роки на створення компілятора, щоб конкурувати з GCC. Вам не потрібно вивчати абсолютно нову мову або вимагати від інших людей. Все, що вам потрібно зробити, - це автоматизувати цю маленьку область, а все інше залишається таким же. Робота виконана.


Однак перевага тексту на основі XML полягає лише в тому, що при необхідності він може читати і писати людьми (вони зазвичай не турбуються, коли це працює, але, безумовно, це роблять під час розробки). Щодо продуктивності та просторової ефективності, бінарні формати, як правило, набагато кращі (що дуже часто не має значення, адже вузьке місце є десь іншим).
близько

@leftaroundabout Якщо вам потрібна ця продуктивність та ефективність простору, обов'язково. Причина, по якій сьогодні багато програм перейшли до форматів на основі XML, полягає в тому, що продуктивність та ефективність простору - це не найкращі критерії, якими вони були колись, і історія показала, як погано підтримуються формати бінарних файлів. (Старі документи MS Word для класичного прикладу!) Однак все ще залишається суть - текст так само підходить для комп'ютерів для читання, як і люди.
Грем

Звичайно, погано розроблений бінарний формат може насправді працювати гірше, ніж правильно продуманий текстовий формат, і навіть пристойний бінарний формат часто не набагато більш компактний, ніж XML, укомплектований деяким алгоритмом стиснення загального призначення. ІМО найкраще з обох світів - використовувати специфіку, що читається людиною, через алгебраїчні типи даних і автоматично генерувати ефективне бінарне представлення з AST цих типів. Дивіться, наприклад, квартирну бібліотеку .
близько

7

Трохи більш прагматична відповідь, зосередившись на тому, чому і ні, що є, а не є вихідним кодом. Зауважте, що генерування вихідного коду є частиною процесу збирання у всіх цих випадках - тому згенеровані файли не повинні знаходити собі шлях до управління джерелом.

Сумісність / простота

Візьмемо буфери протоколів Google, головний приклад: ви пишете єдиний опис протоколу високого рівня, який потім можна використовувати для генерації реалізації на декількох мовах - часто різні частини системи написані різними мовами.

Причини втілення / технічні причини

Візьміть TypeScript - браузери не можуть його інтерпретувати, тому процес збирання використовує транспілятор (код для перекладача коду) для створення JavaScript. Насправді багато нових або езотеричних скомпільованих мов починаються з перенесення на C, перш ніж вони отримують належний компілятор.

Простота використання

Для вбудованих проектів (думаю, IoT), написаних на C та використовуючи лише одну двійкову (RTOS або відсутність ОС), досить легко створити масив C із даними, які збираються так, як якщо б звичайний вихідний код, а не мав на увазі їх безпосередньо як ресурси.

Редагувати

Розширення на протобуф: генерація коду дозволяє згенерованим об'єктам бути першокласними класами на будь-якій мові. У мові компіляції загальний аналізатор, за необхідності, поверне структуру ключових значень - це означає, що ви набули багато кодового шаблону, ви пропустите деякі перевірки часу компіляції (зокрема, для клавіш та типів значень), отримаєте гірші показники та відсутність заповнення коду. Уявіть усіх тих, хто void*в C або величезний std::variantв C ++ (якщо у вас є C ++ 17), деякі мови можуть взагалі не мати такої функції.


З першої причини, я думаю, що ідеєю ОП було б зробити загальну реалізацію на кожній мові (яка бере опис буферів протоколів, а потім аналізує / споживає прямого формату). Чому це буде гірше, ніж генерувати код?
Paŭlo Ebermann

@ PaŭloEbermann, крім звичайного аргументації perfromance, така загальна інтерпретація унеможливить використання цих повідомлень як першокласних об'єктів у складених (і, можливо, інтерпретованих) мовах - у C ++, наприклад, такий інтерпретатор за необхідності повертає структуру ключа-значення. . Звичайно, ви можете отримати цей kv у свої класи, але він може перетворитись у безліч кодових кодів. І також є заповнення коду. І перевірка часу компіляції - ваш компілятор не перевірить, чи немає у ваших літералах помилок друку.
Ян Дорняк

Я згоден ... ви могли б додати це у відповідь?
Paŭlo Ebermann

@ PaŭloEbermann виконано
Ян Дорняк

6

Чи генерація вихідного коду є антитілом?

Це обробка недостатньо вираженої мови програмування. Немає необхідності генерувати код мовою, яка містить адекватне вбудоване метапрограмування.


3
Це також вирішення того, що потрібно писати повний компілятор коду, що переходить до рідного об'єкта, для більш вираженої мови. Створіть C, нехай компілятор з хорошим оптимізатором подбає про інше.
Blrfl

Не завжди. Іноді у вас є одна або кілька баз даних, що містять деякі визначення, наприклад, сигнали на шині. Тоді ви хочете зібрати цю інформацію разом, можливо, зробіть кілька перевірок узгодженості, а потім напишіть код, який взаємодіє між сигналами, що надходять з шини, та змінними, які ви очікуєте у своєму коді. Якщо ви можете показати мені мову, яка має метапрограмування, що полегшує користування деякими наданими клієнтом аркушами Excel, базою даних та іншими джерелами даних та створює потрібний мені код, з деякими необхідними перевірками на достовірність та послідовність даних, всі засоби покажіть мені.
CodeMonkey

@CodeMonkey: щось на кшталт реалізації ActiveRecord Ruby on Rails приходить на думку. Немає необхідності дублювати схему таблиці бази даних у коді. Просто нанесіть клас на таблицю і запишіть бізнес-логіку, використовуючи назви стовпців як властивості. Я не уявляю собі будь-якого шаблону, який міг би бути створений генератором коду, який також не міг би керуватися метапрограмуванням Ruby. Шаблони C ++ також надзвичайно потужні, хоч і трохи таємничі. Макроси Lisp - ще одна потужна мовна система метапрограмування.
Кевін Клайн

@kevincline, що я мав на увазі код, який базувався на деяких даних із бази даних (можна було побудувати з неї), але не самій базі даних. Тобто у мене є інформація про те, які сигнали я отримую в таблиці Excel A. У мене є база даних B з інформацією про ці сигнали тощо. Зараз я хочу мати клас, який отримує доступ до цих сигналів. Немає підключення до бази даних або аркуша Excel на машині, що працює з кодом. Використання дійсно складного C ++-шаблонів для створення цього коду під час компіляції замість простого генератора коду. Я підберу кодеген.
CodeMonkey

6

Генерація вихідного коду не завжди є антитілом. Наприклад, я зараз пишу фреймворк, який за даною специфікацією генерує код двома різними мовами (Javascript та Java). Рамка використовує створений Javascript для запису дій браузера користувача та використовує код Java в Selenium для фактичного виконання дії, коли фреймворк знаходиться в режимі повторного відтворення. Якби я не використовував генерацію коду, я повинен був би вручну переконатися, що обидва завжди синхронізовані, що є громіздким, а також певним чином логічним дублюванням.

Якщо все-таки використовується генерація вихідного коду для заміни таких функцій, як дженерики, то це анти-шаблон.


Можна, звичайно, один раз написати свій код в ECMAScript і запустити його в Nashorn або Rhino на JVM. Або ви можете написати JVM в ECMAScript (або спробувати скласти Avian в WebAssembly за допомогою Emscripten) і запустити свій код Java у браузері. Я не кажу, що це чудові ідеї (ну, це, мабуть, жахливі ідеї :-D), але принаймні вони можливі, якщо не здійсненні.
Йорг W Міттаг

Теоретично це можливо, але це не загальне рішення. Що станеться, якщо я не можу запустити одну з мов всередині іншої? Наприклад, додаткова річ: я просто створив просту модель Netlogo, використовуючи генерацію коду, і маю інтерактивну документацію системи, яка завжди синхронізується з рекордером та програвачем. І взагалі, створення вимоги, а потім генерування коду зберігає речі, які семантично працюють разом у синхронізації.
Христо Вригазов

6

Я чогось тут пропускаю?

Може бути хорошим прикладом, коли причиною успіху виявився посередницький код? Я можу запропонувати вам HTML.

Я вважаю, що для HTML було важливо бути простим та статичним - це спрощувало створення браузерів, дозволяло рано запускати мобільні браузери тощо. Як показали подальші експерименти (аплети Java, Flash) - більш складні та потужні мови призводять до появи більше проблем . Виявляється, що користувачі фактично знаходяться під загрозою Java-аплетів, а відвідування таких веб-сайтів було настільки ж безпечним, як і спроби ігрових тріщин, завантажених через DC ++. Звичайний HTML, з іншого боку, досить нешкідливий, щоб ми могли перевірити будь-який сайт з розумною вірою в безпеку нашого пристрою.

Однак HTML не був би десь там, де він є зараз, якби він не був створений комп'ютером. Моя відповідь навіть не з’явиться на цій сторінці, поки хтось вручну не переписав її з бази даних у HTML-файл. На щастя, ви можете зробити корисний HTML практично будь-якою мовою програмування :)

Тобто, якщо для чогось є генератор коду, то чому б не зробити це чимось належною функцією, яка може приймати необхідні параметри і робити правильні дії, які б зробив код "сгенерований"?

Чи можете ви уявити собі кращий спосіб відобразити запитання та всі відповіді та коментарі користувачеві, ніж використовувати HTML як створений код між проміжками?


Так, я можу уявити собі кращий спосіб. HTML - це спадщина рішення Тіма Бернерса-Лі дозволити швидке створення текстового веб-браузера. На той час це було прекрасно, але ми б не зробили те саме з користю заднього огляду. CSS зробив непотрібними всі типи елементів презентації (DIV, SPAN, TABLE, UL тощо).
Кевін Клайн

@kevincline Я не кажу, що HTML як такий є без вад, я вказував на те, що введення мови розмітки (що може бути сформовано програмою) в цьому випадку спрацювало дуже добре.
Джуріс

Тож HTML + CSS кращий, ніж просто HTML. Я навіть написав внутрішню документацію для деяких проектів, над якими працював безпосередньо в HTML + CSS + MathJax. Але, здається, більшість веб-сторінок, які я відвідую, створені генераторами коду.
Девід К

3

навіщо генерувати вихідний код?

Тому що це швидше і простіше (і менш схильне до помилок), ніж писати код вручну, особливо для виснажливих, повторюваних завдань. Ви також можете використовувати інструмент високого рівня для перевірки та затвердження дизайну перед тим, як написати єдиний рядок коду.

Загальні випадки використання:

  • Інструменти моделювання, такі як троянда або візуальна парадигма;
  • Високовольтний ер мови на рівні , як Embedded SQL або мова визначення інтерфейсу , який повинен бути препроцесор в щось компільовані;
  • Генератори Лексера та парсера, такі як флекс / зубр;

Що стосується вашого "чому не просто зробити його функцією та передати їй параметри безпосередньо", зауважте, що жодне з перерахованого вище не є середовищем виконання саме по собі. Немає можливості зв’язати свій код з ними.


2

Іноді у вашій мові програмування просто немає необхідних можливостей, тому неможливо писати функції або макроси, щоб робити те, що ви хочете. Або, можливо, ви могли б робити те, що хочете, але код, щоб написати це було б некрасиво. Простий скрипт Python (або подібний) може потім генерувати необхідний код як частину вашого процесу збирання, який ви потім #includeперетворите у фактичний вихідний файл.

Звідки я це знаю? Оскільки це рішення, якого я неодноразово досягав під час роботи з різними різними системами, останнім часом SourcePawn. Простий скрипт Python, який розбирає простий рядок вихідного коду і виробляє два-три рядки згенерованого коду, набагато краще, ніж створювати згенерований код вручну, коли ви отримуєте два десятки таких рядків (створюючи всі мої квартали).

Демонстративний / прикладний вихідний код доступний, якщо люди цього хочуть.


1

Текстова форма потрібна для легкого споживання людиною. Комп'ютери також обробляють код у текстовій формі досить легко. Тому згенерований код повинен формуватися у формі, яку найпростіше створити та простіше споживати на комп’ютерах, і це дуже часто читабельний текст.

І коли ви генеруєте код, сам процес генерації коду часто потребує налагодження - люди. Це дуже, дуже корисно, якщо згенерований код читається людиною, щоб людина могла виявити проблеми в процесі генерації коду. Хтось повинен написати код для створення коду, зрештою. Це не відбувається з повітря.


1

Генеруючий код, лише один раз

Не все генерування вихідного коду є випадком генерування якогось коду, а потім ніколи його не торкаючись; потім регенерує його з початкового джерела, коли воно потребує оновлення.

Іноді ви генеруєте код лише один раз, а потім відкидаєте початкове джерело і, рухаючись вперед, підтримуєте нове джерело.

Це іноді трапляється при перенесенні коду з однієї мови на іншу. Особливо, якщо не очікується, що згодом захоче перенести нові зміни оригіналу (наприклад, старий код мови не підтримуватиметься, або він фактично є повним (наприклад, у випадку математичної функції)).

Один поширений випадок полягає в тому, що написання генератора коду для цього може лише фактично перекласти 90% коду правильно. і тоді останні 10% потрібно зафіксувати вручну. Що набагато швидше, ніж перекладати 100% вручну.

Такі генератори коду часто сильно відрізняються від типу генераторів коду, що f2cвиробляють повноцінні перекладачі (як Cython або ). Оскільки мета - один раз зробити підтримку коду. Їх часто роблять 1 раз, щоб робити саме те, що їм потрібно. Багато в чому це версія наступного рівня використання регулярного коду / пошуку-заміни для коду порту. Ви можете сказати, що "перенесення портів за допомогою інструментів".

Генерування коду, лише один раз, наприклад, з подряпини веб-сайту.

Тісно пов'язане це, якщо ви генеруєте код з якогось джерела, ви не хочете знову отримати доступ. Наприклад, якщо дії, необхідні для створення коду, не повторюються, не є послідовними, або їх виконання є дорогим. Зараз я працюю над парою проектів: DataDeps.jl та DataDepsGenerators.jl .

DataDeps.jl допомагає користувачам завантажувати дані (наприклад, стандартні набори даних ML). Для цього йому потрібно те, що ми називаємо реєстраційний блок. Це якийсь код, який визначає деякі метадані, наприклад, звідки завантажувати файли, контрольну суму та повідомлення, що пояснює користувачеві будь-які умови / кодиції / що таке статус ліцензування для даних.

Написання цих блоків може дратувати. І ця інформація часто доступна (структурована чи неструктурована) з веб-сайтів, на яких розміщуються дані. Тож DataDepsGenerators.jl використовує веб-комбайн для генерації RegistrationBlockCode для деяких сайтів, на яких розміщено багато даних.

Можливо, їх генерується неправильно. Тож розробник, що використовує згенерований код, може і повинен перевірити та виправити його. Швидше за все, вони хочуть переконатися, що, наприклад, інформація про ліцензування не пропустила скребки.

Важливо, що користувачам / розробникам, які працюють з DataDeps.jl, не потрібно встановлювати або використовувати веб-комбайн, щоб використовувати створений код RegistrationBlock. (І не потрібно завантажувати та встановлювати веб-скрепер, це економить неабияк часу. Особливо для запуску CI)

Згенерування вихідного коду один раз не є антипаттерном. і це, як правило, не може бути замінено метапрограмуванням.


"report" - англійське слово, яке означає щось інше, ніж "порт знову". Спробуйте "повторно перенести", щоб це речення було зрозумілішим. (Коментує, що занадто мала для запропонованої редакції.)
Пітер Кордес

Хороший улов @PeterCordes Я перефразував.
Ліндон Уайт

Швидше, але потенційно набагато менш рентабельне, залежно від того, наскільки жахливим є створений код. Від Fortran до C це було ще в ті часи (компілятори C були широко доступні, тому люди могли використовувати f2c+ cc), але отриманий код насправді не був гарною відправною точкою для версії програми C, AFAIK.
Пітер Кордес

1
Потенційно, потенційно ні. Не в тому, що в генераторі коду є помилкою, що деякі генератори коду роблять нерентабельний код. Зокрема, ручний інструмент, який не повинен вловлювати кожен випадок, часто може зробити ідеально хороший код. Якщо, наприклад, 90% коду - це лише список констант масиву, то генерування таких конструкторів масивів як єдине ціле може бути зроблено дуже красиво та за малих зусиль. (З іншого боку, виведення коду C Cython не може підтримуватися людьми. Тому що це не призначено. Так само, як ви говорите для f2cтого часу)
Ліндон Уайт

1
Великий стіл був просто найпростішим аргументованим. Аналогічне можна сказати і для перетворення скажу для циклів або умов. Дійсно sedйде довгий шлях, але іноді потрібно трохи більше виразної сили. Межа між логікою програми та даними часто є тонкою. Іноді розмежування не корисне. JSON - це (/ був) просто код конструктора об’єктів JavaScript. У моєму прикладі я також генерувати об'єкт конструктор код (це його дані можуть бути (може бути , не так , іноді він має виклики функції) краще розглядати як код да?.?.)
Ліндон White

1

Генерація "вихідного" коду - це ознака недоліку мови, що формується. Чи використовуєте інструменти для подолання цього антитіла? Абсолютно ні - дозвольте пояснити.

Зазвичай генерація коду використовується, оскільки існує визначення вищого рівня, яке може описувати отриманий код набагато менш багатослівним, ніж мова нижчого рівня. Таким чином, генерування коду полегшує ефективність та стійкість.

Коли я пишу c ++, я це роблю, тому що це дозволяє мені писати код більш ефективно, ніж використовувати асемблер або машинний код. Ще машинний код генерується компілятором. На початку, c ++ був просто препроцесором, який генерував код C. Мови загального призначення чудово підходять для формування поведінки загального призначення.

Таким же чином, за допомогою DSL (мови, визначеної для домену) можна записати короткий, але, можливо, код, обмежений певним завданням. Це зробить менш складним формувати правильну поведінку коду. Пам’ятайте, що код - це засіб для закінчення . Що розробник шукає - це ефективний спосіб генерувати поведінку.

В ідеалі генератор може створювати швидкий код із входу, який простіше маніпулювати та розуміти. Якщо це виконано, не використовується генератор - це антитіла . Цей анти-візерунок зазвичай походить від думки, що "чистий" код є "чистішим", так само, як деревообробник чи інший майстер може дивитись на використання електроінструменту або використання ЧПУ для "генерації" заготовок (думайте золотистими молоток ).

З іншого боку, якщо джерелом згенерованого коду важче підтримувати або генерувати недостатньо ефективний код, користувач потрапляє у пастку використання неправильних інструментів (колись через той же золотий молоток ).


0

Генерація вихідного коду абсолютно не означає, що сформований код є даними. Але це дані першого класу, дані, якими решта програми може управляти.

Дві найпоширеніші типи даних, які мені відомі, і які інтегруються у вихідний код, - це графічна інформація про Windows (кількість та розміщення різних елементів управління) та ORM. В обох випадках інтеграція за допомогою генерації коду спрощує маніпулювання даними, оскільки для їх використання не потрібно пройти додаткові "спеціальні" кроки.

Під час роботи з оригінальними (1984 р.) Mac, діалогові та віконні визначення були створені за допомогою редактора resouce, який зберігав дані у двійковому форматі. Використовувати ці ресурси у вашій програмі було складніше, ніж було б, якби "бінарний формат" був Pascal.

Отже, ні, генерація вихідного коду не є антидіаграмою, вона дозволяє зробити частину даних додатком, що полегшує її використання.


0

Генерація коду є антидіаграмою, коли вона коштує більше, ніж досягає. Така ситуація виникає, коли покоління відбувається від A до B, де A є майже тією ж мовою, що і B, але з деякими незначними розширеннями, які можна було б виконати просто кодуванням в A з меншими зусиллями, ніж усі спеціальні інструменти та побудова постановки для A до B .

Компроміс є більш забороненим щодо генерування коду на мовах, які не мають засобів метапрограмування (структурних макросів) через ускладнення та недоліки досягнення метапрограмування шляхом постановки зовнішньої обробки тексту.

Погана торгівля також може стосуватися кількості використання. Мова A може істотно відрізнятися від B, але весь проект із спеціальним генератором коду використовує лише A в одному або двох невеликих місцях, так що загальна кількість складності (невеликі біти A, плюс генератор коду A -> B, плюс постановка оточуючої збірки) перевищує складність рішення, щойно зробленого в Б.

В основному, якщо ми беремо на себе генерацію коду, нам, мабуть, слід "піти великим або йти додому": зробити його суттєвою семантикою і використовувати його багато, або не турбувати.


Чому ви видалили абзац "Коли Bjarne Stroustrup вперше реалізував C ++ ..." абзац? Я думаю, це було цікаво.
Утку

@Utku Інші відповіді висвітлюють це з точки зору складання цілої, витонченої мови, якою решта проекту повністю написана. Я не думаю, що це представник більшості того, що називається "генерація коду".
Каз

0

Я не бачив цього чітко (я бачив, що це торкнулося однією або двома відповідями, але це не здавалося дуже зрозумілим)

Генерування коду (як ви сказали, як би це були дані) не є проблемою - це спосіб повторно використовувати компілятор для другорядних цілей.

Редагування згенерованого коду - це одна з найбільш підступних, злих, жахливих анти-моделей, які ви коли-небудь стикаєтеся. Не роби цього.

У кращому випадку редагування згенерованого коду втягує купу поганого коду у ваш проект (ЦІЛЬКИЙ набір коду тепер справді ДЖЕРЕЛ КОД - більше даних). У гіршому випадку код, утягнутий у вашу програму, є надмірним, погано названим сміттям, яке майже повністю неможливе.

Я припускаю, що третьою категорією є код, який ви використовуєте один раз (gui generator?), А потім редагуйте, щоб допомогти вам розпочати / вивчити. Це трохи з кожного - це МОЖЖЕ бути гарним способом запустити, але ваш генератор графічного інтерфейсу буде орієнтований на використання коду "Generatable", який не стане чудовим початком для вас як програміста. Крім того, ви можете бути спокусився використати його ще раз для другого GUI, що означає втягнути зайвий код ДЖЕРЕЛА у вашу систему.

Якщо ваш інструмент досить розумний, щоб заборонити будь-які редагування згенерованого коду, перейдіть до цього. Якщо ні, то я б назвав це одним із найгірших анти-моделей.


0

Код і дані обидва: Інформація.

Дані - це інформація саме у потрібній вам формі (і значенні). Код - це також інформація, але в непрямій або проміжної формі. По суті, код також є формою даних.

Більш конкретно, код - це інформація для машин, щоб вивантажити людину від самої обробки інформації.

Звільнення людини від обробки інформації - найважливіший мотив. Проміжні кроки прийнятні до тих пір, поки вони полегшують життя. Ось чому існують проміжні засоби відображення інформації. Як генератори коду, компілятори, транспілятори тощо.

навіщо генерувати вихідний код? Чому б не перетворити його на функцію, яка може приймати параметри і діяти на них?

Скажімо, хтось пропонує вам таку функцію відображення, реалізація якої вам незрозуміла. Поки функція працює, як було обіцяно, чи будете ви хвилюватися, чи внутрішньо вона генерує вихідний код чи ні?


0

Якщо щось можна створити, то ця річ - це дані, а не код.

Оскільки ви згодом указуєте, що цей код є даними, ваша пропозиція зводиться до "Якщо щось можна створити, то ця річ не є кодом". Ви б сказали, що код складання, сформований компілятором C, не є кодом? Що робити, якщо це точно збігається з кодом складання, який я пишу вручну? Ви можете поїхати туди, якщо хочете, але я не буду їхати з вами.

Почнемо замість цього з визначення "коду". Не надто надто технічне, досить непоганим визначенням для цілей цієї дискусії буде "машино-прийнятні інструкції щодо проведення обчислень".

Враховуючи це, чи не вся ця ідея створення вихідного коду є непорозумінням?

Ну так, ваша початкова пропозиція полягає в тому, що код не може бути створений, але я відкидаю цю пропозицію. Якщо ви приймаєте моє визначення поняття "код", тоді не повинно виникнути концептуальної проблеми з генерацією коду взагалі.

Тобто, якщо для чогось є генератор коду, то чому б не зробити це чимось належною функцією, яка може приймати необхідні параметри і робити правильні дії, які б зробив код "сгенерований"?

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

Чому тоді ви віддаєте перевагу писати на Java чи C чи Lisp чи ще? Навіть асемблер? Я запевняю, що це хоча б частково, оскільки ці мови надають абстракції для даних та операцій, що полегшують вираження деталей обчислень, які ви хочете виконати.

Те саме стосується і більшості генераторів коду вищого рівня. Прототипічні випадки - це, ймовірно, генератори сканерів та аналізаторів, такі як lexі yacc. Так, ви можете написати сканер і аналізатор безпосередньо на C або в будь-якій іншій мові програмування на ваш вибір (навіть сировинному машинному коді), а іноді і так. Але для проблеми будь-якої значної складності використання спеціальної мови вищого рівня, такої як lex або yacc, полегшує написання, читання та підтримку рукописного коду. Зазвичай і значно менші.

Ви також повинні врахувати, що саме ви маєте на увазі під "генератором коду". Я б вважав попередню обробку C та інстанціювання шаблонів C ++ вправами для генерації коду; чи заперечуєте проти цього? Якщо ні, то, я думаю, вам потрібно буде виконати певну розумову гімнастику, щоб раціоналізувати їх прийняття, але відхилити інші аромати генерування коду.

Якщо це робиться з міркувань продуктивності, то це звучить як недолік компілятора.

Чому? Ви в основному заявляєте, що у вас повинна бути універсальна програма, до якої користувач подає дані, деякі класифікуються як "інструкції", а інші - як "вхідні дані", і яка переходить до виконання обчислень та видає більше даних, які ми називаємо "вихідними". (З певної точки зору, таку універсальну програму можна назвати "операційною системою".) Але чому ви вважаєте, що компілятор повинен бути настільки ефективним для оптимізації такої програми загального призначення, як і для оптимізації більш спеціалізованої програми програма? Дві програми мають різні характеристики та різні можливості.

Якщо це робиться для з'єднання двох мов, то це звучить як брак бібліотеки інтерфейсів.

Ви кажете, що як би мати універсальну до певної міри бібліотеку інтерфейсів обов'язково було б хорошою справою. Можливо, це було б, але в багатьох випадках така бібліотека була б великою і складною для написання та обслуговування, а може, навіть повільною. І якщо такого звіра насправді не існує для того, щоб слугувати конкретній проблемі, то хто це ти, щоб наполягати на тому, щоб його створити, коли підхід до генерації коду може вирішити проблему набагато швидше та простіше?

Я чогось тут пропускаю?

Я думаю, кілька речей.

Я знаю, що код також є даними. Що я не розумію, чому генерувати вихідний код? Чому б не перетворити його на функцію, яка може приймати параметри і діяти на них?

Генератори коду перетворюють код, написаний однією мовою, на код іншою, як правило, нижчою мовою. Тоді ви запитуєте, чому люди хочуть писати програми, використовуючи кілька мов, і особливо, чому вони можуть хотіти змішувати мови суб'єктивно різних рівнів.

Але я вже торкнувся цього. Кожен вибирає мову для певного завдання, частково спираючись на його чіткість та виразність для цього завдання. Оскільки менший код має менше помилок у середньому і його легше обслуговувати, існує також ухил до мов вищого рівня, принаймні для масштабної роботи. Але складна програма передбачає багато завдань, і часто деякі з них можна ефективніше вирішувати однією мовою, тоді як інші ефективніше чи більш стисло розглядаються на іншій. Використання правильного інструменту для роботи іноді означає використання коду.


0

Відповідь на питання в контексті Вашого коментаря:

Обов’язком компілятора є взяти код, написаний у читаній людиною формі, і перетворити його в машиночитану форму. Отже, якщо компілятор не може створити ефективний код, тоді компілятор не виконує свою роботу належним чином. Це неправильно?

Компілятор ніколи не буде оптимізований під ваше завдання. Причина цього проста: оптимізовано робити багато завдань. Це інструмент загального призначення, який використовується багатьма людьми для багатьох різних завдань. Після того, як ви дізнаєтеся, у чому полягає ваше завдання, ви можете наблизитись до коду в залежності від домену, зробивши компроміси, які компілятори не змогли.

Як приклад, я працював над програмним забезпеченням, де аналітику може знадобитися написати якийсь код. Вони могли записати свій алгоритм на C ++ і додати в усі межі перевірки та прийоми запам'ятовування, від яких вони залежать, але для цього потрібно знати багато про внутрішню роботу коду. Вони вважають за краще написати щось просте, і дозвольте мені накинути на нього алгоритм, щоб генерувати остаточний код C ++. Тоді я можу робити екзотичні хитрощі, щоб досягти максимальної продуктивності, як статичний аналіз, який я ніколи не очікував, що мої аналітики перетерплять. Генерація коду дозволяє їм писати в доменному режимі, що дозволяє їм виводити продукт у двері простіше, ніж будь-який інструмент загального призначення.

Я також зробив навпаки. У мене є ще один твір, який я виконував, маючи мандат "без генерації коду". Ми все ще хотіли полегшити життя тим, хто використовує програмне забезпечення, тому ми використовували величезну кількість метапрограмування шаблонів, щоб змусити компілятор генерувати код на льоту. Таким чином, мені потрібна була лише мова загального призначення C ++, щоб виконувати свою роботу.

Однак є улов. Було надзвичайно важко гарантувати, що помилки читаються. Якщо ви коли-небудь використовували шаблон метапрограмування шаблону раніше, ви знаєте, що одна невинна помилка може генерувати помилку, яка займає 100 рядків незрозумілих назв класів та аргументів шаблону, щоб зрозуміти, що пішло не так. Цей ефект був настільки виражений, що рекомендований процес налагодження помилок синтаксису був "Прокручуйте журнал помилок, доки ви вперше не побачите помилку в одному з власних файлів. Перейдіть до цього рядка і просто прижмуріться до нього, поки не зрозумієте, що ви зробив не так ".

Якби ми використовували генерацію коду, ми могли б мати набагато більш потужні можливості управління помилками, з людськими помилками. Це життя.


0

Існує кілька різних способів використання коду. Їх можна розділити на три основні групи:

  • Генерування коду іншою мовою як вихід із кроку в процесі компіляції. Для типового компілятора це була б мова нижчого рівня, але це могла бути й інша мова високого рівня, як у випадку з мовами, які компілюються в JavaScript.
  • Генерування або перетворення коду мовою вихідного коду як крок у процесі компіляції. Це те, що роблять макроси .
  • Створення коду за допомогою інструменту окремо від звичайного процесу компіляції. Вихід з цього коду є кодом, який живе у вигляді файлів разом із звичайним вихідним кодом і компілюється разом із ним. Наприклад, класи сутностей для ORM можуть бути автоматично згенеровані за допомогою схеми бази даних, або об'єкти передачі даних та сервісні інтерфейси можуть бути сформовані з специфікації інтерфейсу, як файл WSDL для SOAP.

Я б припустив, що ви говорите про третій вид згенерованого коду, оскільки це найбільш суперечлива форма. У перших двох формах згенерований код є проміжним кроком, який дуже чітко відокремлений від вихідного коду. Але в третій формі немає формального поділу між вихідним кодом та згенерованим кодом, за винятком того, що згенерований код, мабуть, має коментар, який говорить "не редагуйте цей код". Це все ще відкриває ризик розробникам редагувати згенерований код, який був би справді некрасивим. З точки зору компілятора, згенерований код є вихідним кодом.

Тим не менш, такі форми згенерованого коду можуть бути дійсно корисними в мові, що вводиться статично. Наприклад, при інтеграції з об'єктами ORM дуже корисно мати сильно набрані обгортки для таблиць бази даних. Впевнені, що ви могли динамічно працювати з інтеграцією під час виконання, але ви втратите безпеку типу та підтримку інструментів (доповнення коду). Основною перевагою мови статичного типу є підтримка системи типів на типі запису, а не просто під час виконання. (І навпаки, цей тип генерації коду не надто поширений у динамічно набраних мовах, оскільки в такій мові він не дає ніякої користі порівняно з перетвореннями часу виконання).

Тобто, якщо для чогось є генератор коду, то чому б не зробити це чимось належною функцією, яка може приймати необхідні параметри і робити правильні дії, які б зробив код "сгенерований"?

Оскільки безпека типу та заповнення коду - це функції, які ви хочете під час компіляції (і під час написання коду в IDE), але регулярні функції виконуються лише під час виконання.

Однак може бути середнє місце: F # підтримує концепцію провайдерів типів, яка в основному є сильно типізованими інтерфейсами, створеними програмно під час компіляції. Ця концепція, ймовірно, може замінити багато використання генерації коду та забезпечити більш чітке розділення проблем.


0

Набори інструкцій для процесорів принципово необхідні , але мови програмування можуть бути декларативними . Запуск програми, написаної декларативною мовою, неминуче вимагає певного генерування коду. Як згадується у цій відповіді та інших, головна причина для генерування вихідного коду на зрозумілій людині мові полягає в тому, щоб скористатися складними оптимізаціями, що виконуються компіляторами.


-3

Якщо щось можна створити, то ця річ - це дані, а не код.

Ви зрозуміли це неправильно. Це слід прочитати

Якщо щось можна подати в генератор для інтерпретацій , то ця річ - код, а не дані.

Це вихідний формат для цього етапу компіляції, а формат мийки - все ще код.


1
Неправильне визначення вихідного коду . Вихідний код здебільшого стосується людей, які працюють над ним (і саме цей факт визначає його, дивіться також, що таке вільне програмне забезпечення FSF). Код ассемблера, що генерується за допомогою gcc -fverbose-asm -O -S, не є вихідним кодом (і є не лише або здебільшого даними), навіть якщо це текстова форма, яка завжди подається в GNU asі іноді читається людиною.
Базиль Старинкевич

Крім того, багато мовних реалізацій компілюються в код C , але створений C не є справжнім вихідним кодом (наприклад, людина не може легко працювати з ним).
Базиль Старинкевич

Нарешті, ваше обладнання (наприклад, ваш AMD чи Intel чип або материнська плата комп'ютера) інтерпретує машинний код (який, очевидно, не є вихідним кодом). BTW У IBM1620 був машинописний код (BCD), але цей факт не зробив його "вихідним кодом". Весь код не є вихідним.
Василь Старинкевич

@BasileStarynkevitch Ах, ти мене туди завів. Мені не слід занадто сильно стискати свою дотепну заяву, або вони змінюють своє значення. Правильно, вихідний код повинен бути самим оригінальним кодом, який подається на першому етапі компіляції.
Бергі

Жоден вихідний код не є кодом для людей. Так само важко і так само суб'єктивно визначити, як музика (проти звуку). Справа не в тому, щоб намагатися знайти програмне забезпечення, яке його споживає.
Базиль Старинкевич
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.