Введение

Расширяемое программирование — термин, используемый в информатике для описания стиля программирования, ориентированного на механизмы расширения языка программирования, компилятора и среды выполнения (окружения). Языки программирования, поддерживающие такой стиль, активно разрабатывались в 1960-х годах, но это направление отошло на второй план в 1970-х годах.

Историческое движение

Первая работа, обычно ассоциируемая с движением расширяемых языков программирования, – это статья М. Дугласа Макилроя 1960 года о макросах для языков программирования высокого уровня. Другое раннее описание принципа расширяемости встречается в статье Брукера и Морриса 1960 года о компиляторе компиляторов. Пик движения был отмечен двумя академическими симпозиумами в 1969 и 1971 годах. К 1975 году в обзорной статье о движении Томаса А. Стендиша Simula была представлена как расширяемый язык на конференции 1969 года. Стендиш описал три класса языковых расширений, которые он назвал парафразой, ортофразой и метафразой (иначе парафраза и метафраза – это термины перевода). Парафраза определяет возможность, показывая, как заменить её чем-то, что было определено ранее (или будет определено). В качестве примеров он упоминает определения макросов, обычные определения процедур, грамматические расширения, определения данных, определения операторов и расширения структуры управления. Ортофраза добавляет в язык функции, которые невозможно реализовать, используя базовый язык, например, добавление системы ввода/вывода (I/O) в базовый язык, который ранее не имел примитивов I/O. Расширения следует понимать как ортофразы относительно данного базового языка, поскольку функция, не определенная в терминах базового языка, должна быть определена в терминах какого-либо другого языка. Это соответствует современному понятию плагинов. Метафраза изменяет правила интерпретации, используемые для существующих выражений. Это соответствует современному понятию рефлексивного программирования (рефлексии).

Смерть исторического движения

Стандиш объяснил неудачу движения расширяемости сложностью программирования последовательных расширений. Программист может создать первый слой макросов вокруг базового языка. Затем, если вокруг него будет создан второй слой макросов, любому последующему программисту необходимо будет досконально знать как базовый язык, так и первый слой. Третий слой потребует знания базового языка, а также первого и второго слоев, и так далее. Целью движения абстракции, которое заменило движение расширяемости, является защита программиста от деталей нижнего уровня. Несмотря на то, что Simula изначально представлялся как расширяемый язык, обзор Стендиша 1975 года, по всей видимости, на практике не включал новые технологии, основанные на абстракции (хотя он использовал очень широкое определение расширяемости, которое технически могло бы их охватывать). История абстракции программирования, опубликованная в 1978 году и охватывающая период от изобретения компьютера до того времени, не упоминала макросы и не содержала никаких указаний на то, что движение расширяемых языков когда-либо существовало. Макросы были условно приняты движением абстракции к концу 1980-х годов (возможно, благодаря появлению гигиенических макросов), получив название синтаксические абстракции.

Современное движение

В современном понимании система, поддерживающая расширяемое программирование, предоставляет все возможности, описанные ниже.

Расширяемый синтаксис

Это просто означает, что исходные языки, для которых производится компиляция, не должны быть закрытыми, жёстко заданными или статичными. Должна быть возможность добавлять в эти исходные языки новые ключевые слова, понятия и структуры. Языки, допускающие добавление конструкций с синтаксисом, определяемым пользователем, включают Coq, Racket, Camlp4, OpenC++, Seed7, Red, Rebol и Felix. Хотя некоторые фундаментальные и неотъемлемые особенности языка могут быть неизменными, система не должна основываться исключительно на этих особенностях. Должна быть возможность добавлять новые.

Расширяемое время работы

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

Содержание отделено от формы

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

Поддержка отладки исходного языка

Расширяемые системы программирования должны поддерживать отладку программ, используя конструкции исходного языка, независимо от расширений или преобразований, которым программа подверглась для обеспечения ее выполнения. Важно отметить, что нельзя исходить из предположения, что единственный способ отображения данных во время выполнения – это структуры или массивы. Отладчик, или, точнее, "инспектор программы", должен обеспечивать отображение данных времени выполнения в формах, соответствующих исходному языку. Например, если язык поддерживает структуру данных для бизнес-процесса или рабочего процесса, отладчик должен иметь возможность отображать эту структуру данных в виде диаграммы Исикавы (диаграммы рыбьей кости) или другой формы, предоставляемой плагином.