Что такое метапрограммирование
Перейти к содержимому

Что такое метапрограммирование

  • автор:

Метапрограммирование

Шаблон: Просмотр • программирования, связанный с созданием программ, которые порождают другие программы как результат своей работы [1] (в частности, на стадии компиляции их исходного кода), либо программ, которые меняют себя во время выполнения (самомодифицирующийся код). [источник не указан 1251 день] Первое позволяет получать программы при меньших затратах времени и усилий на кодирование, чем если бы программист писал их вручную целиком, второе позволяет улучшить свойства кода (размер и быстродействие).

Генерация кода

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

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

Реализуется двумя основными методами:

  • Шаблоны (наиболее известные случаи применения — препроцессорСи и шаблоны в C++)
  • Внеязыковые средства (пример: генераторы синтаксических и лексических анализаторовlex, yacc, bison)
  • В Perl существует понятие «source filters» («фильтров исходного кода») — метода переработки файлов с исходным кодом перед выполнением, позволяющего полностью менять синтаксис и семантику языка. Одним из известных примеров является модуль Lingua::Romana::Perligata, позволяющий писать код Perl на латыни. [2]
  • В Форт программисту предоставляют встроенные в язык возможности по изменению своего синтаксиса и семантики. Это достигается определением архитектуры виртуальной машины и полного доступа к возможностям изменения её составляющих.

Самомодифицирующийся код

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

Основные методы реализации:

  • Интроспекция — представление внутренних структур языка в виде переменных встроенных типов с возможностью доступа к ним из программы.
  • Пространство имён System.Reflection и тип System.Type в .NET; классы Class, Method, Field в Java; представление пространств имен и определений типов через встроенные типы данных в Python; стандартные встроенные возможности в Форт по доступу к ресурсам виртуальной машины; получение значения и изменение свойств почти любого из объектов в ECMAScript (с оговорками).
  • Интерпретация произвольного кода, представленного в виде строки.
    • Существует естественным образом во множестве интерпретируемых языков, например, eval() в PHP.
    • Компилятор Tiny C позволяет «на лету» компилировать и исполнять код на языке C, представленный в виде строки символов.
    • Для Форт использования процедуры интерпретации из строки EVALUATE.

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

    См. также

    Примечания

    1. Джонатан Бартлетт, Искусство метапрограммирования, Часть 1: Введение в метапрограммирование
    2. Lingua::Romana::Perligata — search.cpan.org
    3. Метакидес, Нероуд, 1998

    Литература

    • Метакидес Г., Нероуд А. Принципы логики и логического программирования = Principles of Logic and Logic Programming. — М .: Факториал, 1998. — С. 252-253. — 288 с. — ISBN 5-88688-037-2

    Ссылки

    • R# — метапрограммирование в .Net
    • BOOST MPL LIBRARY (англ.) — библиотека для метапрограммирования с использованием шаблонов C++
    • Boost Preprocessor Library (англ.) — библиотека для метапрограммирования с использованием препроцессора C++
    • Статья об ещё одном подходе к метапрограммированию (англ.)
    • Клаус Крэфт, Анжелика Лангер. Шаблоны выражений (expression templates). Часть 1Часть 2
    • Джонатан Бартлетт, Искусство метапрограммирования, Часть 1: Введение в метапрограммирование
    • Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное.
    • Проставив сноски, внести более точные указания на источники.
    • Добавить иллюстрации.
    • Парадигмы программирования

    Wikimedia Foundation . 2010 .

    Метапрограммирование

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

    UPD: Более новая статья: Метапрограммирование с примерами на JavaScript. И лекция по статье на Youtube (лекция записана в Киевском политехническом институте 18 апреля 2019 года в рамках курса «100 видео-лекций по программированию»):

    Итак, попробую дать альтернативное определение: метапрограммирование — это парадигма построения кода информационной системы с динамическим изменением поведения или структуры в зависимости от данных, действий пользователя или взаимодействия с другими системами. Задачи метапрограммирования: повышение абстракции кода и его гибкости, повторное использование, ускорение разработки, упрощение межсистемной интеграции. На самом деле, все мы в той или иной мере используем метапрограммирование, я даже сейчас могу вспомнить, как использовал его 15 лет назад, даже не подозревая как оно называется, тогда я еще не мог провести какой-либо классификации.

    Какие мы знаем техники метапрограммирования (я надеюсь, что меня дополнят):

    1. Компилируемые техники
    1.1. Шаблоны, макросы и параметрический полиморфизмом. Для одного блока кода на этапе прекомпиляции генерируется несколько вариантов для разных типов параметров, это самый древний тип матапрограммирования.
    1.2. Оптимизирующая прекомпиляция. Вычисление и оптимизация всех выражений и целых функций, которые не содержат переменных, на этапе компиляции или прекомпиляции.
    1.3. Генераторы исходного кода для компилируемых языков. Перед компиляцией, на этапе сборки проекта, пакетным образом, по метаданным или без их, генерируются файлы, функции, классы, формы и т.д.
    1.4. Написание своего предметно-ориентированного компилируемого языка (под определенный круг задач) — DSL (Domain-specific Programming Language).

    2. Интерпретируемые техники
    2.1. Эвалуациея кода (eval) из строковых переменных в интерпретируемых языках или языках, поддерживающих позднюю компиляцию в байт-код во время исполнения.
    2.2. Написание своего специализированного интерпретируемого императивного языка под задачу (LOP — Language Oriented Programming).
    2.3. Создание или использование декларативного языка, формата сериализации, специального синтаксиса или подмножества таких синтаксисов как XML, JSON, XAML и др.
    2.4. Динамическое формирование и исполнение кода на языках запросов, например: SQL, XQuery, LINQ и др.

    3. Гибридные техники
    3.1. Интроспекция — предоставление доступа к внутренним структурам языка, типам данных, классам, функциям и т.д. Получение метаданных о структурах и обход их в цикле, или получение параметров функции как массива с возможностью анализировать класс каждого.
    3.2. Динамическая интерпретация метамоделей. Специальная терминология для этого типа еще не разработана, точнее, она не устоялась, поэтому я опишу его подробнее ниже. А тут же дам приведу основную особенность: метамодель (модель предметной области на мета-языке) содержит как императивные так и декларативные компоненты влияющие друг на друга, а приложение становится «виртуальной машиной» для запуска метамодели.
    3.3. Распределенная информационная система с динамическим связыванием на базе интерпретации метамоделей. Это применение пункта (3.2) к клиент-серверному или межсистемному взаимодействию.

    Динамическая прикладная среда для бизнес-объектов

    Теперь подробнее о динамической интерпретации мета-моделей. Как же императивные и декларативные конструкции влияют друг на друга? Понятно, мы анализируем декларативные описатели — некий формализованный формат данных, регулярную грамматику, которую можно без труда отпарсить регулярными выражениями, строковыми операциями или берем уже готовый парсер (например, JSON или XML). Таким образом, императивный алгоритм может менять структуру и последовательность исполнения кода. Но более того, мета-модель содержит еще и интерпретируемые скрипты для выражения бизнес-логики, скрипты получают уже развернутую в памяти декларативную часть мета-модели в свое полное распоряжение и могут обращаться к библиотеками. Тут все подумали про JavaScript конечно. Замечу, что скрипты из мета-модели не имеют доступа к интраспекции «виртуальной машины», а только к данным и метаданным, т.е. к модели предметной области. Такой скрипт может не знать даже, где он запущен, на клиенте или на сервере. Прикладная среда — это прослойка между прикладной моделью и операционной системой, позволяющая виртуализировать прикладное приложение, отвязывая его от системы и платформы.

    Облачные технологии и виртуализация сейчас поднялись только до уровня инфраструктуры и платформы, следующий же, прикладной уровень практически не затронут. Все более четко проявляется потребность в новой архитектуре прикладных приложений. Сервисная архитектура (SOA), несомненно позволяет удовлетворить большинство нужд корпоративных систем, однако, в силу своей тяжеловесности, статичности и сложности разработки, только крупные компании могут себе позволить разработку ПО в этой технологии. Это обусловлено сложным технологическим циклом создания ПО, включающем проектирование, программирование, отладку, тестирование, сборку, доставку пользователю, инсталляцию, настройку и поддержку. Каждая новая версия прикладной системы требует множества шагов для того, чтобы стать доступной на рабочем месте пользователя. А переход между версиями сопряжен со сложностями конвертации данных и обратной совместимости форматов обмена данными и форматов файлов. Все это является результатом следующих особенностей архитектуры программных систем:
    1. Смешивание в программном коде абстракций разного уровня внутри одного класса или модуля. Например, реализация чтения/записи из БД, бизнес-логики и визуализации в одном классе.
    2. Высокая связанность кода двух смежных абстрактных слоев приложения. С односторонней или двухсторонней зависимостью слоев. Например, отдельный оконный АРМ или веб-интерфейс жестко привязаны к набору функций серверного API, их параметрам, типам данных и классам, а серверное приложение привязано жестко к структуре таблиц в базе данных. Часто, высокая связанность выражена в наличии зашитых в коде идентификаторов классов и функций, интерфейсов и параметров, таблиц и полей.
    3. Сборочно-ориентированный жизненный цикл и компиляция бизнес-моделей в машинный код или в байт-код с последующий ручным развертыванием на сервере.
    4. Жесткая фиксация интерфейсов между модулями системы и сетевых интерфейсов (по структуре, параметрам вызова и типам данных).

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

    Теперь инвертируем 4 причины негибкости систем с помощью различных техник метапрограммирования и получим рецепт для систем с динамической интерпретацией метамодели:
    1. Разделение абстракций разного уровня в программном коде. Например, уровень визуальных компонентов, уровень сетевого транспорта, уровень библиотеки прикладных алгоритмов и уровень бизнес-модели могут не быть связаны друг с другом на этапе компиляции среды, однако, связи будут динамически построены на основе метаданных в момент запроса к соответствующему функционалу и закешированы до момента изменения метамодели.
    2. Отсутствие прямых и обратных зависимостей в абстрактных слоях приложения, использование техник метапрограммирования, интраспекции, декларативных и активных языков для описания бизнес-объектов. При этом, внутренняя связанность классов внутри бизнес-модели может быть повышена.
    3. Использование компиляции для уровня прикладной среды и принципа интерпретации для уровня бизнес-моделей. Для среды жизненный цикл остается сборочным, а вот бизнес-модель может изменяться хоть каждую минуту без повторного развертывания.
    4. Введение динамических интерфейсов между модулями (описываемых декларативными языками) и сетевых интерфейсов поддерживающих интраспекцию на уровне сетевого протокола для взаимодействия приложений с динамической структурой и параметрами.

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

    Распределенная информационная система с динамическим связыванием

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

    Десерт

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

    Императивная часть:
    $(function() < var Images = $("#sky div"); var Timers = []; Images.each(function() < fly = function(Id, Range, Duration, Direction) < var Way1 = <>; var Way2 = <>; Way1[Direction] = '+=' + Range; Way2[Direction] = '-=' + Range; $('#' + Id).animate(Way1, Duration).animate(Way2, Duration); > var Image = $(this); var var Range = Image.attr('data-fly-range'); var Duration = parseInt(Image.attr('data-fly-duration')); var Direction = Image.attr('data-fly-direction'); Timers[Id] = setInterval( 'fly("' + Id + '","' + Range + '",' + Duration + ',"' + Direction + '")', Duration * 2 ); fly(Id, Range, Duration, Direction); >); >); 

    Метапрограммирование

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

    Метакод​

    В языке lsFusion в качестве средства метапрограммирования используется метакод, который описывается инструкцией META . Метакод состоит из заголовка и блока кода на языке lsFusion, описывающего последовательность инструкций. Этот блок кода должен завершаться ключевым словом END . Рассмотрим пример метакода, который позволяет добавить на произвольную форму два действия:

    META addActions(formName)  EXTEND FORM formName  PROPERTIES() showMessage, closeForm  ; END 

    В первой строке приведенного примера находится заголовок метакода. Он состоит из ключевого слова META , имени метакода и списка параметров. В данном примере метакод addActions имеет один параметр formName . Это имя формы, на которую будут добавлены действия. Рассмотрим возможные варианты использования этого метакода, которые описываются инструкцией @ .

    @addActions(documentForm); @addActions(orderForm); 

    Инструкция использования метакода обозначается специальным символом @ , затем идет имя метакода и передаваемые параметры. При генерации кода каждый параметр метакода будет заменен на значение, передаваемое в качестве параметра инструкции @ , во всех местах использования параметра метакода. В данном примере параметр метакода formName будет заменяться на documentForm и на orderForm . Приведенные выше использования метакода порождают следующий блок кода:

    EXTEND FORM documentForm  PROPERTIES() showMessage, closeForm ; EXTEND FORM orderForm  PROPERTIES() showMessage, closeForm ; 

    Объединение лексем​

    Простой подстановки идентификатора вместо параметра метакода часто бывает недостаточно. Например, при создании большого количества новых элементов системы внутри метакода нужно иметь возможность задавать эти новые имена. Передавать все имена в качестве параметров метакода бывает неудобно. Поэтому в метакоде существует специальная операция ## , которая работает на уровне лексем. Эта операция может объединить две соседние лексемы в одну. Если же одна из объединяемых лексем является строковым литералом, то результатом объединения будет один строковый литерал.

    META objectProperties(object, caption)  object##Name 'Имя '##caption = DATA BPSTRING[100](object);  object##Type 'Тип '##caption = DATA Type (object);  object##Value 'Стоимость '##caption = DATA INTEGER (object); END @objectProperties(Document, 'документа'); 

    Результатом использования метакода objectProperties будет следующий код:

    DocumentName 'Имя документа' = DATA BPSTRING[100](Document); DocumentType 'Тип документа' = DATA Type (Document); DocumentValue 'Стоимость документа' = DATA INTEGER (Document); 

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

    Примеры​

    META objectProperties(object, type, caption)  object##Name 'Имя'##caption = DATA BPSTRING[100](###object); // делаем заглавной первую букву  object##Type 'Тип'##caption = DATA type (###object);  object##Value 'Стоимость'##caption = DATA INTEGER (###object); END META objectProperties(object, type)  @objectProperties(object, type, ''); END 

    Что такое метапрограммирование

    Что такое метапрограммирование и какие методы есть

    В этой статье вы прочитаете что такое метапрограммирование и какие методы для его реализации есть.

    Также прочитайте статью: «Декларативный подход к программированию», там тоже интересно и полезно.

    Что такое метапрограммирование:

    Метапрограммирование — это группа методов программирования, которые позволяют вам писать программы, которые создают другие программы или обрабатывают их как ваши данные.

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

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

    Это также может помочь удалить повторяющийся код в программе. Язык, на котором написана метапрограмма, называется метаязыком.

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

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

    Методы метапрограммирования:

    Теперь рассмотрим какие есть методы метопрограммирования, всего их три, рассмотрим все.

    Первый способ:

    Первый способ раскрыть внутреннюю структуру программы во время выполнения с помощью API (интерфейса прикладного программирования).

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

    Она также может управлять этими структурами — например, запускать новые программы во время выполнения. классы, изменить реализацию уже определенных методов и т.д. Это всегда зависит от конкретного языка программирования, его свойств и динамики.

    Второй способ:

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

    Часто это строки , которые динамически компилируются и интерпретируются как исходный код во время выполнения.

    Помимо формы интерпретируемой строки, программист также может влиять на контекст, в котором интерпретируется результирующий исходный код.

    В результате буквально «программы могут создавать программы».

    Третий способ:

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

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

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

    Статические языки:

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

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

    Перед окончательной компиляцией программы мы решаем, какие части использовать (например, используя условия в макросах) и компилировать, а какие части «отбросить» во время компиляции. Примерами таких методов являются макросы на C или шаблоны на C++.

    Вывод:

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

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *