Доклад был сделан 3 марта 2004 года на семинаре по языкам, компиляторам и анализу программ (матмех СПбГУ). Про порождающее программирование (generative programming) были сказаны общие слова; тяжёлой задачей оказалось дать «введение в XML и XSLT за 30 минут» (фактически потребовалось 60 минут); основной целью было предложить модель языка XSLT (или его диалекта) для генерации программ и высказать идеи по расширению XSLT.
Определений ГП много. Общее:
Важно, отличие от просто генерации:
Основная книга: “Generative Programming — Methods, Tools, and Applications” by Krzysztof Czarnecki and Ulrich W. Eisenecker. Научая книга. В Теркоме она есть. Видел как книгу и как ксеру.
Словосочетание “generative programming” пока не переводится. Возможный вариант: «порождающее программирование».
[картинка]
Problem Space
Configuration Knowledge
Solution Space
Solution Space — «Пространство решений» — то, чем оперирует заказчик (высокоуровневые компоненты, семейства продуктов).
Problem Space — «Пространство задачи» — то, чем оперирует разработчик
Configuration Knowledge — настройки по умолчанию, зависимости, правила построения, невозможные комбинации, оптимизации
С problem space связано понятие: DSL — domain-specific languague — язык предметной области
Естественные пути реализации: специальные языки (не обязательно текстовые) или расширения существующих.
Есть риск при использовании DSL. Наплодив макросов, можно получить несопровождаемую программу. С другой стороны, без DSL никак. Философы любят об этом говорить.
Для хранения configuration knowledge разработаны свои системы и языки. Большая тема для разговора.
Есть различные техники: ОО анализ и дизайн, Feature Modeling. Главное — не упустить важных деталей и не запутаться в них. Второе важнее.
Изобретатель: Чарльз Симони, Chief Architect at Microsoft Research, автор «венгерской нотации».
Естественная практика: код разбивается на логические кусочки. IP идёт дальше: эти кусочки должны представляться в наглядном виде (например, графически).
Почти пример: построители интерфейса пользователя (Delphi и компания). Почти, так как это отельный режим. А в IP, если, например, используется картинка, то она может быть представлена сама собой прямо в коде программы.
Есть снимки экрана со внутренней разработки Microsoft. Расширяемая IDE.
Для матриц и сложных математических выражений — очень полезная штука.
AOP: по использования это ближе к Solution Space, по воздействию на код — к Problem Space
Надо отделить маленькие, противные детали, пронизывающие код.
Пример: есть стек или список (из предметной области). В какой-то момент появляются нити, надо добавлять синхронизацию, и в код надо внедрять что-то, не имеющее отношение к предметной области.
Аспекты: вкрапления кода, не имеющие отношения к действительному назначению кода.
Утверждается, что AOP-инструменты могут помочь с этим справиться: и код остаётся нормальным, и аспекты отделяются и внедряются. Как — не знаю, надо смотреть. Например, AspectJ.
внешние (макросы, обрабатываемые препроцессором)
встроенные (например, шаблоны C++)
«Старый мир»:
Чего добивались: удобное переключение между режимами выводом токенов и режимом исполнения, неизбыточность, возможность передачи параметров. (Современный веб-вариант: миф о разделении содержания и представления.) Вершина творения: xslt, lisp.
«Новый мир», веб:
«Круговорот шаблонов». Есть язык шаблонов (php 1). В нём появляются циклы и т.д. (php 2, 3). Он становится языком программирования (php 4). Для него появляется язык шаблонов (smarty).
Metaprogramming — приставка “meta” хороша для PhD-диссертаций
generics: C++ templates, а теперь и Java и .NET
C++ template metaprogramming. Книга: Андрей Александреску, «Современное проектирование на C++».
partial specialization + lazy instantiation + требования вычислять константы могут быть использованы для создания функционального языка, интерпретируемого компилятором.
[code]
template<int N>
struct Factorial {
enum { value = N * Factorial::value };
};
struct Factorial<1> {
enum { value = 1 };
};
int f7 = Factorial<7>;
[/code]
Primzahlen von Erwin Unruh — выводит список простых чисел в виде сообщений об ошибках компиляции.
«Я всегда думал, что шаблоны C++ — это изобретения Дьявола, и теперь я в этом полностью уверен.»
Польза:
XML есть семейство технологий для обработки структурированных данных (особенно деревянных). Метаязык. Универсальность. Аналогия с ASCII.
[code] <article id="hw"> <title>Hello</title> <para>Hello, <object>World</object>!</para> </article> [/code]
Методы обработки: SAX, DOM, XPath
SAX:
DOM:
Xpath для XML — это как SQL для RDBS, особенно в версии 2.0. Иногда XPath применять жалко: связать с domain-specific optimization. Мне пока эти работы неизвестны, хотя и должны быть.
И SAX, и DOM достаточно сложны из-за низкоуровенности. Идеальная обработка: смесь SAX, DOM и XPath. Этим является XSLT.
Всё просто, но спецификация запутана.
<... xmlns:u="eeefff">...<u:type/>...</..>
имя не “u:type”, но “{eeefff}type”
Модульность: можно смешать xhtml с mathml с svg и т.д.
Связь namespaces с intentional programming. Вообще, как XML может представлять понятия GP.
Можно «оторвать знания» от компилятора и представить в удобном виде. Эти знания можно будет переносить между между разными компиляторами. Особенно полезно было бы реализовать знания об XPath.
Можно разработать XML-представления языка шаблонов. Если есть реализация чего-то на одном языке шаблонов (например, C++ STL) и появляется новый компилятор с новыми шаблонами (какой-нибудь .NET), то можно будет полуавтоматически перенести реализацию на новую систему.
Рассказать:
Вывод:
XSLT vs свой велосипед: базовая модель проста, но есть очень большой набор «идиоматических выражений». Для XSLT они уже разработаны, узнаваемы (некоторым присвоены имена) и многократно описаны, для велосипеда — вряд ли.
Модель:
Примерная структура xslt-файла:
[code] <x:stylesheet xmlns:x="http://www.w3.org/1999/XSL/Transform" version="1.0"> ... <x:key ... /> ... <x:template match="..."> ... </x:template> ... </x:stylesheet> [/code]
Примеры:
вернуться к разделу «генерация кода», показать, что задачи выполнимы
x:with-param распространяется на всё дерево
x:generate-id
x:key (как элемент xslt и как функция xpath)
[code] <items> <item gr="a">item 1</item> <item gr="a">item 2</item> <item gr="b">item 3</item> <item gr="a">item 4</item> <item gr="b">item 5</item> </items> [/code]
[code]<x:key name="groups" match="item" use="@gr"/>[/code]
[code]... select="key('groups','a')" ...[/code]
выбрать самые первые узла в своих классах (после освоения можно считать, что знаешь xslt)
[code]
<x:apply-templates select="item[ generate-id(.) = generate-id(key('groups',@gr)) ]"/>
[/code]
двухуровневая группировка (после освоения можно считать, что понимаешь xslt)
Проблема: выбор правила, когда “match” должен быть сложным
Возможно, есть связь с “tree rewriting”
Вещь сама в себе. Нет контроля. Не всегда уверены, что отработали правильно.
Во входных данных иерархия должна быть явной.
Мало функций (решение: расширения и exslt).
Что надо: XSLT нужен как язык программирования. Тут засада. И не в том, что функций мало, а в том, что деревья, xpath, xslt-процесс и его ключи должны быть «объектами первого класса» в базовом языке программирования.
Чем расширять? Если каким нибудь традиционным, то опять возникают проблемы неудобной работы с деревом. Расширять xslt с помощью xslt. Что-то типа макросов. Но ведь есть функциональный язык с макросами и кучей скобок (только круглых, а не угловых) — Lisp. К тому же, есть реализации для встраивания в свои приложения.
Подход XSLT реализуется на Lisp'e очень просто. Важно реализовать сам xslt, чтобы почти всё работало. Особенно важно, чтобы классические «идиоматические выражения» без проблем распознавались человеком.