Перейти к основному содержимому
Версия: 7.0

Расширение действий

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

Абстрактное действие задает контракт расширения: классы параметров определяют допустимые реализации, а при необходимости действие может также объявлять класс результата и классы его параметров.

Расширение действий позволяет:

  • Реализовывать концепцию полиморфизма действий по аналогии с некоторыми объектно-ориентированными языками программирования.
  • Убирать зависимость между модулями, добавляя определенные "точки входа" для позднего добавления нового поведения.

Выбор реализации

Какая именно реализация будет выполнена, зависит от формы абстрактного действия:

  • В явной условной форме каждая реализация имеет собственное условие выбора.
  • В сигнатурной полиморфной форме реализация выбирается по совместимости классов текущих аргументов с ее сигнатурой.
  • В последовательной форме одна реализация не выбирается: выполняются все добавленные реализации.

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

Порядок реализаций

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

Это влияет на поведение следующим образом:

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

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

Полнота набора реализаций

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

Такое требование делает контракт расширения сильнее: при добавлении новых более частных случаев необходимо одновременно добавлять и соответствующие реализации.

Контракт реализации

Каждая реализация абстрактного действия имеет собственную сигнатуру параметров. Платформа соотносит эту сигнатуру с контрактом абстрактного действия.

Реализация не должна неявно сужать область применимости абстрактного действия. Иначе сигнатура реализации перестает соответствовать контракту абстрактного действия.

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

Асинхронная пометка реализации

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

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

Полиморфная форма

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

Взаимоисключаемость условий

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

Язык

В этой технике используются две языковые конструкции: оператор ABSTRACT для объявления абстрактного действия и инструкция ACTION+ для добавления к нему реализации.

Примеры

exportXls 'Выгрузить в Excel' ABSTRACT CASE OVERRIDE LAST (Order);
exportXls (Order o) + WHEN name(currency(o)) == 'USD' THEN {
MESSAGE 'Export USD not implemented';
}

CLASS ABSTRACT Task;
run 'Выполнить' ABSTRACT MULTI EXCLUSIVE FULL (Task);

CLASS Task1 : Task;
name = DATA STRING[100] (Task);
run (Task1 t) + {
MESSAGE 'Run Task1 ' + name(t);
}
CLASS ABSTRACT Animal;
whoAmI ABSTRACT ( Animal);

CLASS Dog : Animal;
whoAmI (Dog d) + { MESSAGE 'I am a dog!'; }

CLASS Cat : Animal;
whoAmI (Cat c) + { MESSAGE 'I am a cat!'; }

ask () {
FOR Animal a IS Animal DO
whoAmI(a);
}

CLASS Sku;
name = DATA STRING[100] (Sku);
onStarted ABSTRACT LIST ();
onStarted () + {
name(Sku s) <- '1';
}
onStarted () + {
name(Sku s) <- '2';
}

CLASS Human;
name = DATA STRING[100] (Human);

testName ABSTRACT CASE ( Human);

testName (Human h) + WHEN name(h) == 'John' THEN { MESSAGE 'I am John'; }
testName (Human h) + WHEN name(h) == 'Bob' THEN { MESSAGE 'I am Bob'; }

CLASS Issue;
CLASS Language;
localizedTitle = DATA STRING[100] (Issue, Language);

getLocalizedTitle(Issue issue) ABSTRACT STRING[100] (Language);
getLocalizedTitle (Issue issue) + {
FOR Language l IS Language DO
RETURN localizedTitle(issue, l);
}