Метапрограммирование - это метод программирования, при котором компьютерные программы имеют возможность обрабатывать другие программы как свои данные. Это означает, что программа может быть разработана для чтения, генерации, анализа или преобразования других программ и даже для изменения самой себя во время работы. В некоторых случаях это позволяет программистам минимизировать количество строк кода для выражения решения, что, в свою очередь, сокращает время разработки. Это также дает программам большую гибкость для эффективной обработки новых ситуаций без перекомпиляции.
Метапрограммирование может использоваться для перемещения вычислений из времени выполнения во время компиляции, для генерации кода с использованием вычислений во время компиляции и для включения самомодифицирующегося кода. Способность языка программирования быть собственным метаязыком называется рефлексией. Отражение - ценная языковая функция, облегчающая метапрограммирование.
Метапрограммирование было популярно в 1970-х и 1980-х годах с использованием языков обработки списков, таких как LISP. Аппаратные машины LISP были популярны в 1980-х годах и позволяли приложениям обрабатывать код. Они часто использовались для приложений искусственного интеллекта.
Метапрограммирование позволяет разработчикам писать программы и разрабатывать код, подпадающий под общую парадигму программирования. Наличие самого языка программирования как первоклассного типа данных (как в Lisp, Prolog, SNOBOL или Rebol ) также очень полезно; это известно как гомоиконность. Универсальное программирование вызывает средство метапрограммирования в языке, позволяя писать код, не заботясь об указании типов данных, поскольку они могут быть предоставлены как параметры при использовании.
Метапрограммирование обычно работает одним из трех способов.
Лисп, вероятно, является наиболее существенным языком со средствами метапрограммирования, как из-за его исторического приоритета, так и из-за простоты и мощности его метапрограммирования. В метапрограммировании Лиспа оператор отмены кавычек (обычно запятая) вводит код, который оценивается во время определения программы, а не во время выполнения; см. Самооценку форм и цитирование в Лиспе. Таким образом, язык метапрограммирования идентичен основному языку программирования, а существующие процедуры Lisp при желании могут быть напрямую повторно использованы для метапрограммирования. Этот подход был реализован на других языках путем включения в программу интерпретатора, который работает непосредственно с данными программы. Есть реализации такого рода для некоторых языков общего высокого уровня, таких как RemObjects ' Pascal Script для Object Pascal.
Простым примером метапрограммы является сценарий POSIX Shell, который является примером генеративного программирования :
#!/bin/sh # metaprogram echo '#!/bin/sh' gt; program for i in $(seq 992) do echo "echo $i" gt;gt; program done chmod +x program
Этот сценарий (или программа) генерирует новую программу из 993 строк, которая выводит числа 1–992. Это только иллюстрация того, как использовать код для написания большего количества кода; это не самый эффективный способ распечатать список чисел. Тем не менее, программист может написать и выполнить эту метапрограмму менее чем за минуту и за это время сгенерирует более 1000 строк кода.
Куайн это особый вид метапрограммы, который производит свой собственный исходный код своей продукции. Квайны обычно представляют только развлекательный или теоретический интерес.
Не все метапрограммирование включает в себя генеративное программирование. Если программы можно изменять во время выполнения или доступна инкрементная компиляция (например, в C #, Forth, Frink, Groovy, JavaScript, Lisp, Elixir, Lua, Nim, Perl, PHP, Python, REBOL, Ruby, Rust, SAS, Smalltalk, и Tcl ), тогда методы могут использоваться для выполнения метапрограммирования без фактического создания исходного кода.
Один из стилей генеративного подхода - использование предметно-ориентированных языков (DSL). Довольно распространенный пример использования DSL включает в себя генеративное метапрограммирование: lex и yacc, два инструмента, используемых для создания лексических анализаторов и синтаксических анализаторов, позволяющих пользователю описывать язык с помощью регулярных выражений и контекстно-свободных грамматик и встраивать сложные алгоритмы, необходимые для эффективного синтаксического анализа язык.
Одно из применений метапрограммирования - инструментальные программы для выполнения динамического анализа программ.
Метапрограммирование может использоваться для внесения поведенческих изменений в программу, как это делается в аспектно-ориентированном программировании. Например, метапрограммирование может использоваться для внедрения флагов функций или для изучения возможных патчей для исправления ошибок.
Некоторые утверждают, что для полноценного использования функций метапрограммирования требуется резкая кривая обучения. Поскольку метапрограммирование дает большую гибкость и настраиваемость во время выполнения, неправильное или неправильное использование метапрограммирования может привести к неоправданным и неожиданным ошибкам, отладить которые среднему разработчику может быть чрезвычайно сложно. Он может создать риски для системы и сделать ее более уязвимой, если не использовать ее с осторожностью. Некоторые из распространенных проблем, которые могут возникнуть из-за неправильного использования метапрограммирования, - это неспособность компилятора идентифицировать отсутствующие параметры конфигурации, недопустимые или неверные данные могут привести к неизвестному исключению или другим результатам. В связи с этим некоторые считают, что только высококвалифицированные разработчики должны работать над разработкой функций, которые осуществляют метапрограммирование на языке или платформе, а средние разработчики должны научиться использовать эти функции в рамках соглашения.
IBM / 360 и производные были мощные макроассемблера объектов, которые часто используются для создания полной сборки языковых программ или разделов программ (для различных операционных систем, например). Макросы, поставляемые с системой обработки транзакций CICS, содержат макросы ассемблера, которые генерируют операторы COBOL в качестве этапа предварительной обработки.
Другие ассемблеры, такие как MASM, также поддерживают макросы.
Метаклассы предоставляются следующими языками программирования:
Использование зависимых типов позволяет доказать, что сгенерированный код никогда не является недействительным. Однако этот подход является передовым и редко встречается за пределами исследовательских языков программирования.
Список известных систем метапрограммирования поддерживается в Списке систем преобразования программ.