Порождающее программирование (generative programming) и язык XSLT

Доклад был сделан 3 марта 2004 года на семинаре по языкам, компиляторам и анализу программ (матмех СПбГУ). Про порождающее программирование (generative programming) были сказаны общие слова; тяжёлой задачей оказалось дать «введение в XML и XSLT за 30 минут» (фактически потребовалось 60 минут); основной целью было предложить модель языка XSLT (или его диалекта) для генерации программ и высказать идеи по расширению XSLT.

I. Введение в GP

Определений ГП много. Общее:

Важно, отличие от просто генерации:

Основная книга: “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. Главное — не упустить важных деталей и не запутаться в них. Второе важнее.

Intentional Programming

Изобретатель: Чарльз Симони, Chief Architect at Microsoft Research, автор «венгерской нотации».

Естественная практика: код разбивается на логические кусочки. IP идёт дальше: эти кусочки должны представляться в наглядном виде (например, графически).

Почти пример: построители интерфейса пользователя (Delphi и компания). Почти, так как это отельный режим. А в IP, если, например, используется картинка, то она может быть представлена сама собой прямо в коде программы.

Есть снимки экрана со внутренней разработки Microsoft. Расширяемая IDE.

Для матриц и сложных математических выражений — очень полезная штука.

Aspect-Oriented Programming

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++ — это изобретения Дьявола, и теперь я в этом полностью уверен.»

Польза:

III. XML, XPath

XML есть семейство технологий для обработки структурированных данных (особенно деревянных). Метаязык. Универсальность. Аналогия с ASCII.

[code]
<article id="hw">
 <title>Hello</title>
 <para>Hello, <object>World</object>!</para>
</article>
[/code]

Методы обработки: SAX, DOM, XPath

SAX:

DOM:

Xpath

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 и т.д.

XML и порождающее программирование

Связь namespaces с intentional programming. Вообще, как XML может представлять понятия GP.

Можно «оторвать знания» от компилятора и представить в удобном виде. Эти знания можно будет переносить между между разными компиляторами. Особенно полезно было бы реализовать знания об XPath.

Можно разработать XML-представления языка шаблонов. Если есть реализация чего-то на одном языке шаблонов (например, C++ STL) и появляется новый компилятор с новыми шаблонами (какой-нибудь .NET), то можно будет полуавтоматически перенести реализацию на новую систему.

IV. XSLT

Рассказать:

Вывод:

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]

Примеры:

  • переименование узла
  • default transform
  • identity transform
  • вставить кусок дерева (раздвоить дерево во всех узлах)
  • отрезать кусок дерева
  • вернуться к разделу «генерация кода», показать, что задачи выполнимы

    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)

    V. Проблемы XSLT, дальнейшее развитие

    Проблема: выбор правила, когда “match” должен быть сложным

    Возможно, есть связь с “tree rewriting”

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

    Во входных данных иерархия должна быть явной.

    Мало функций (решение: расширения и exslt).

    Что надо: XSLT нужен как язык программирования. Тут засада. И не в том, что функций мало, а в том, что деревья, xpath, xslt-процесс и его ключи должны быть «объектами первого класса» в базовом языке программирования.

    Чем расширять? Если каким нибудь традиционным, то опять возникают проблемы неудобной работы с деревом. Расширять xslt с помощью xslt. Что-то типа макросов. Но ведь есть функциональный язык с макросами и кучей скобок (только круглых, а не угловых) — Lisp. К тому же, есть реализации для встраивания в свои приложения.

    Подход XSLT реализуется на Lisp'e очень просто. Важно реализовать сам xslt, чтобы почти всё работало. Особенно важно, чтобы классические «идиоматические выражения» без проблем распознавались человеком.


    http://uucode.com/texts/genxslt/genxslt.html
    Oleg A. Paraschenko <olpa uucode com>