Какая польза от метапрограммирования? - PullRequest
69 голосов
/ 12 августа 2010

Я прочитал:

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

У кого-нибудь есть конкретный пример использования метапрограммирования / генерации кода?Еще лучше было бы сопроводительное объяснение, почему это было лучше, чем альтернатива.

edit : Будет ли Thistle считаться метапрограммированием?

Ответы [ 11 ]

111 голосов
/ 12 августа 2010

Представьте себе парня, который строит автомобили.Скажем, это то же самое, что и использование компьютера.
В какой-то момент он понимает, что всегда делает одно и то же, более или менее.
Таким образом, он строит заводы для сборки автомобилей, и это намного лучше.Сейчас он программирует!
Тем не менее, еще раз, в какой-то момент, он понимает, что он всегда делает то же самое, до некоторой степени.
Теперь он решает построить заводы, которые строят заводы, которые производят автомобили.Это метапрограммирование.

Метапрограммирование чрезвычайно мощно, но один сбой в системе превращает все преимущества в трудности монстра.Так что овладей им и используй ... Или держись подальше!

20 голосов
/ 12 августа 2010

Я думаю о метапрограммировании как о «программах, которые пишут (или модифицируют) другие программы».(В другом ответе говорилось: «фабрики, которые делают фабрики», хорошая аналогия).

Люди находят для этого все виды применения: настройка приложений, генерация шаблонного кода, оптимизация программы для особых обстоятельств, реализация DSL, вставка кода врешать проблемы ортогонального проектирования («аспекты») ...

Что примечательно, так это то, что было изобретено много различных механизмов для создания этой части: текстовые шаблоны, макросы, условные выражения препроцессора, универсальные шаблоны, C ++ - шаблоны, аспекты,рефлексия ... И обычно некоторые из этих механизмов встроены в некоторые языки, а другие механизмы - в другие языки, и большинство языков вообще не поддерживают метапрограммирование.Такое точное распределение возможностей означает, что вы можете выполнять некоторые виды метапрограммирования на одном языке с ограничениями, но при этом не можете выполнять такие действия на другом языке.Это отягчает: -}

Наблюдение, которому я следил за рукояткой, состоит в том, что можно создать универсальный механизм метапрограммирования, который работает с любым языком в форме программных преобразований .Программное преобразование - это параметризованный шаблон: «если вы видите этот синтаксис, замените его на этот синтаксис».

Одно само преобразование обычно не впечатляет,но десятки или сотни могут внести впечатляющие изменения в код.Поскольку (сложные) программные преобразования могут фактически имитировать машину Тьюринга, они могут выполнять произвольные изменения кода, включая все те точечные техники, которые вы нашли без разбора.

Инструмент, который принимает определения языка.Специфичные для языка преобразования и генерирующие другое для применения этих преобразований - это meta -метапрограммирующий инструмент: программа для написания «программ, которые пишут программы».

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

Интересный урок заключается в том, что для такого механизма требуется сильная поддержка анализа программ (таблиц символов, управления и анализа потоков данных и т. Д.), Чтобы помочь ему сосредоточиться на проблемах в коде, чтобы механизм метапрограммирования мог что-то делать.в этот момент (очень слабым примером этого являются точечные спецификации в аспектах, которые говорят «вносить изменения в местах, которые похожи на это»).

ФП попросил конкретные примеры того, где было метапрограммированиеприменяется.Мы использовали наш инструмент мета-метапрограммирования ( DMS Software Reengineering Toolkit ) для автоматического выполнения следующих действий с большими базами кода:

  • Языковая миграция
  • Реализация тестового покрытия и профилировщиков
  • Реализация обнаружения клонов
  • Массовая реинжиниринг архитектуры
  • Генерация кода для управления фабрикой
  • SOAizationвстроенные сетевые контроллеры
  • Извлечение архитектуры для программного обеспечения мэйнфреймов
  • Генерация векторных SIMD-команд из вычислений массива
  • Обратный инжиниринг кода обратно к понятиям

на многих языках, включая Java, C #, C ++, PHP, ...

ФП также спросил: «Почему это было лучше, чем альтернатива?»Ответ связан с масштабом, временем и точностью.

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

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

По сути, эти инструменты делают то, что делают людипросто не может.

Стоит отметить, что инструменты не обладают креативностью; ты все еще нужно, чтобы люди определяли, что им делать, например, чтобы решить в чем заключается задача (см. список выше для примеров) и определите как определить анализы / преобразования для достижения эффекта. Вам все еще нужны meta -программисты. Тем не менее, когда метапрограммист вооружить такой инструмент с необходимыми знаниями, результирующий код может похоже, что он создан невероятно быстрым, креативным, опытным программистом.

5 голосов
/ 14 августа 2010

Я получил наибольшее использование из метапрограммирования для соединения между различными API.

Рабочий пример будет FireBreaths JSAPIAuto 1 , что облегчает написаниеКлассы C ++, которые подвергаются JavaScript.Предоставляя средство регистрации для функций, которые должны быть представлены, можно проверять типы аргументов и из этого подходящего кода, сгенерированного во время компиляции, который преобразует типы API-сценариев в собственные типы C ++ и обратно, даже напрямую поддерживая map, vector и т. Д.

В качестве простого примера рассмотрим открытую функцию add(a, b), которая использует некоторые типы API сценариев:

ScriptVariant add(const std::vector<ScriptVariant>& values) {
    // have to check argument count
    if(values.size() != 2)
        throw script_error("wrong number of arguments");

    try {
        // have to convert from scripting-API types
        long a = values[0].convert_cast<long>();
        long b = values[0].convert_cast<long>();
        return a+b; // potentially need to convert back too
    } catch(ScriptVariant::bad_cast& e) {
        // need to handle conversion failure
        throw script_error("conversion failed :(");
    }
}

Фактическая логика, скрытая в ней,только одна строка, что проверки и преобразования раздражают и излишни.С ранее упомянутым средством регистрации (например, в конструкторе):

registerMethod("add", make_method(this, &MyClass::add));

теперь это можно просто записать как:

long add(long a, long b) {
    return a+b;
}

... и каркас заботится о генерациинеобходимый код для вас.

1: Хотя я бы сделал реализацию немного ... чище ... если бы мне пришлось начать заново

3 голосов
/ 12 августа 2010

Я могу привести свой конкретный пример: я разрабатываю ABSE , который является подходом метапрограммирования. С ABSE вы создаете модель (фактически, дерево), где каждый элемент представляет собой «Атом». Этот атом представляет собой «концепцию» и содержит необходимые метаданные для его определения.

В ABSE реализация концепции на самом деле является «мини-программой».

Затем разработчик моделей хоста ( AtomWeaver , разработанный вместе с ABSE) берет модель и «соткает» программу-генератор из всех ее атомов. Затем эта программа запускается, генерируя нужные артефакты (исходный код, данные и т. Д.).

Итак, рабочий процесс ABSE:

  1. Создать дискретную концепцию (часть мета-метапрограммы)
  2. Повторное использование этого понятия в модели (эффективное построение метапрограммы)
  3. Ведущий моделер ткет и запускает метапрограмму
  4. Метапрограмма генерирует вашу окончательную программу

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

Преимущества метапрограммирования (не исключая ABSE)?:

  • Изменение модели и восстановление всей системы (Представьте себе функции рефакторинга вместо исходных строк).
  • Изменение нескольких определений в модели может привести к появлению отдельных программ (семейства программных продуктов).
  • Повторно используя шаблоны, вы можете изменить код шаблона, восстановить и изменить код в десятках, сотнях мест.
  • Многие другие, действительно

Метапрограммирование, генерация кода, трансформация программ - новые захватывающие миры в разработке программного обеспечения, ИМХО. Однако метапрограммирование требует нового навыка: мета-мышление.

Мы можем определить мета-мышление как «мышление о том, как вы думаете о своем собственном развитии». Этакая классовая рефлексия, примененная к себе. На практике вы должны выяснить свои собственные шаблоны разработки, изолировать их, сделать их общими, а затем превратить их в метапрограммы, используя вашу любимую технику, будь то ABSE, DSL, DSM и т. Д.

3 голосов
/ 12 августа 2010

Мой последний (за последние 6 месяцев) конкретный пример генерации кода:

  1. У меня есть сценарий SQL Plus, который генерирует, а затем выполняет другие сценарии SQL Plus. Сгенерированный сценарий выполняет запросы к некоторым таблицам, имеющим поля меток времени, и когда я проектировал сценарий, было невозможно узнать, какое временное окно выбрать. Итак, основной сценарий выполняет свою работу и выясняет, какие временные диапазоны должны быть в подпрограммах. Затем он генерирует подписки, записывая их код в файл (и подставляя заполнители для фактического времени начала и окончания). Наконец, он выполняет индекс (ы). Я использовал этот прием для нескольких ситуаций (хотя зачастую и более сложных, чем этот), когда структура подэтапов зависит от результатов предыдущих шагов.

  2. Однажды я получил элементы отображения электронных таблиц из XSD в столбцы таблицы в базе данных. Можно было генерировать фрагменты XSL и выполнять запросы из электронной таблицы, используя макросы и VBA. Эти фрагменты и запросы были скопированы и вставлены (в основном без изменений) в систему, которая их выполняла и обрабатывала результаты. Не очень удачное решение, но оно, безусловно, сделало очень утомительную работу гораздо менее утомительной, и полученный код, вероятно, выглядел гораздо более последовательным, чем если бы я потратил неделю или две на написание всего этого вручную.

SO список примеров метапрограммирования: Какие самые крутые примеры метапрограммирования вы видели в C ++?

2 голосов
/ 16 августа 2018

Я попытаюсь объяснить мой конкретный пример использования методов метапрограммирования.

Я создал программный инструмент, который будет генерировать исходный код веб-страницы ASP.NET из любой формы ввода данных MS Access. Техника, которую я использовал, заключалась в создании собственных текстовых шаблонов ASP.NET для каждого типа элемента управления формы. Я просто подключил такие значения, как TOP, LEFT, HEIGHT, WIDTH, CONTROLSOURCE из метаданных объектов формы MS Access. Например, мой шаблон для текстового поля ASP.NET выглядит так:

 <asp:TextBox ID="**ID**" runat="server" style="z-index: 1; left: **LL**px; top: **TOP**px; position: absolute"  Text='<%# Bind("[**CTLSOURCE**]") %>' />

после получения значений метаданных элемента управления textbox моя программа генерирует код для текстового поля

<asp:TextBox ID="txtCustomerID" runat="server" style="z-index: 1; left: 50px; top: 240px; position: absolute"  Text='<%# Bind("[CustomerID]") %>' />

Моя программа генерирует весь исходный код веб-страницы для одной формы MS Access за 2-3 секунды. Альтернативой является ручное кодирование веб-страницы ASP.NET с нуля; задача, которая может занять несколько часов или даже дней.

Представьте себе базу данных MS Access с 24-35 формами. Передача кода каждой формы в виде исходного кода веб-страницы ASP.NET может занять недели, если не месяцы. В этом случае использование инструмента преобразования с методами метапрограммирования сокращает время разработки веб-страниц с недель и месяцев до часов.

2 голосов
/ 12 августа 2010

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

Boost полон библиотек (C ++), которыепродемонстрировать, чего можно достичь с помощью метапрограммирования.Вот некоторые хорошие (и, возможно, трудные для понимания) примеры: Proto , которые позволяют реализацию DSL , Spirit , которые позволяют писать компилятор с использованием EBNF грамматика непосредственно в коде и многие другие потрясающие библиотеки.

1 голос
/ 16 августа 2010

Запустите вашу Visual Studio (Eclipse, Netbeans, что угодно еще).Создать новый проект.Сюрприз - вы только что использовали метапрограммирование, создавая проект из шаблона.Разве это не практично?

1 голос
/ 13 августа 2010

Конкретный пример того, где это может быть полезным подходом.

У вас есть набор сторонних классов, к которым вы хотите добавить общее поведение - например, какой-то контроль безопасности / доступа, отображение объектов в виде JSON и т. Д.

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

В примере JSON, используя интроспекцию класса, вы сможете сгенерировать код для сериализации объекта, а затем добавить его как метод в класс. Другие крайности будут генерировать или писать код заранее (до компиляции) и влиять на каждый раз, когда изменяется класс, или полностью универсальный подход, который использует интроспекцию для каждого отдельного объекта, каждый раз, когда вы хотите отобразить его.

В зависимости от рассматриваемого языка и времени выполнения, метапрограммирующий подход, вероятно, будет быстрее, чем полностью универсальный / интроспективный, но медленнее, чем исходный код, так как вы сократили много поисков данных в коде.

Там, где метапрограммирование не существует непосредственно в языке, мне также кажется, что его часто заново изобретают с помощью каркасов (то есть контейнеров в стиле IoC, таких как Spring).

0 голосов
/ 15 апреля 2019

Мы часто используем метапрограммирование для создания свойств в VBA.У нас есть различные электронные таблицы Excel со многими заголовками, и мы хотим определить свойства getter / setter для каждого заголовка, что позволяет нам манипулировать ячейками под этим заголовком.Вручную сделать это было бы кошмаром.

Выбранная нами среда метапрограммирования - Notepad ++ и его возможности поиска / замены регулярных выражений.Вот как мы метапрограммировали наши свойства:

  • Скопируйте список заголовков из Excel в Блокнот ++
  • Запишите макрос Notepad ++ для очистки данных (удалите пробелы и специальные символы),В конце этого у нас есть список строк, разделенных новой строкой.
  • Вручную скопируйте список в другой файл .CSV и используйте Excel для создания списка номеров строк.Затем скопируйте обратно в Блокнот ++.
  • Введите регулярное выражение для преобразования имени свойства в определение свойства, добавив все пробелы, ключевые слова и т. Д. Используйте номер строки в качестве номера столбца в нашем определении свойства.

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

Это сила метапрограммирования.Когда использовать это вопрос опыта / интуиции.Но я рекомендую ответить на этот вопрос:

Будет ли для меня быстрее просто написать это напрямую, или я могу автоматизировать некоторые / все процессы и ускорить мой процесс?

Это дает вам черту, за которой метапрограммирование больше не нужно.Если вы можете просто закодировать это быстрее, даже если это 10 повторений, просто сделайте это!Только если это сотни повторений или что-то, что вы ожидаете многократно использовать в будущем, то запрограммируйте это.

Другой момент - здесь есть градусы.Однажды я написал Java-программу для создания группы файлов для добавления новой проверки IntelliJ в проект кодирования проверок.Это было довольно трудоемко: создать проект Java, скомпилировать его и т. Д. С другой стороны, поиск / замена Notepad ++ - это всего лишь маленький шаг вперед по сравнению с ручным вводом текста самостоятельно.Совет здесь состоит в том, чтобы начать делать вещи вручную, а затем автоматизировать, когда вы видите необходимость, только до такой степени, когда это имеет смысл.Нет необходимости в Java-программе, когда Notepad ++ подойдет.Нет необходимости в Notepad ++ при ручном наборе.

...