Арка: Взаимодействие инструментов-8. Получатель уведомлений

По сути, про получателя уже все сказано в предыдущих записях:

  • в арке, принимающей уведомление, нужна только принимающая команда
  • в схеме (в настройке этой арки) должны быть указаны:
    • путь верстака (через который рассылаются уведомления)
    • имя уведомления
    • имя принимающей команды (здесь только имя, так как это декларативное описание)

В случае необходимости подключится во время работы, в верстаке нужна команда:

тип Верстак = протокол{

фн подключить получателя уведомления(имя-уведомления: Строка, получатель: фн*): Лог

}

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

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

Как в целом происходит взаимодействие, принимая во внимание, что могут быть N отправителей и M получателей?

Думаю, что по принципу «кто первый встал, того и тапки». При первом обращении к верстаку из отправителя или получателя создается «разъем» и фиксируется сигнатура. Все последующие обращения проверяют сигнатуру и не проходят, если сигнатура не совпадает. Как именно не проходят, пока не рассматриваю. Вир использует подход SmallTalk’а — если объекта отправлено сообщения, а у него нет получателя сообщения, то сообщение игнорируется. В Вире есть отладочный режим, в котором такие случаи записываются в журнал, а может быть режим, при котором происходит авария.

Есть ли смысл у верстака (в схеме) задавать разъем с указанием сигнатуры и не полагаться на первое обращение? Не знаю. Это усложняет схему и заставляет думать о порядке инициализации. Впрочем, хорошее взаимодействие всегда идет «через верх». То есть арка взаимодействует через верстак, которые находится выше (ближе к корню). И это неявно определяет время жизни — корень живет дольше всех и порядок инициализации. Компилятор схемы может проверять «хорошесть» взаимодействия.

И еще важно, что проверка сигнатуры может делаться AOT, если все задано в схеме. И тогда разъем верстака может быть сгенерен компилятором схемы (без участия архитектора).

В следующей записи я соберу вместе краткое описание работы с уведомлениями. И там же исправлю ошибку в подключении отправителя (Взаимодействие инструментов-7), сигнатуру, все же, надо передавать, а не только преобразовывать к ней.

3 комментария


  1. > В качестве получателя передаются команда (closure) […]
    >> почему уведомления у вас это не часть «протокола» […]
    > Вопрос очень правильный и я об этом думал. Пока не пришел к решению. […]

    Для Оберона когда-то предлагались «интерфейсы» в рамках проекта Lagoona, интерфейсы как комбинации «независимых closure» — «stand-alone messages». В помощь для коммутации интерфейсов введено понятие метода по умолчанию (исполняемого при «получении» отсутствующего «сообщения» в интерфейсе) и операции перенаправления (делегирования):

    * https://www.inf.utfsm.cl/~mcloud/iwi-253/lecturas/tr-ics-1999-49.pdf
    * http://www.sciencedirect.com/science/article/pii/S0167642304001765/pdf?md5=be654e2fee8f8b47daa4f5f8991fe507&pid=1-s2.0-S0167642304001765-main.pdf

    Ниже выдержка из второй статейки по ссылке выше (там представлена реализация на Net) — «generic»-итератор с «default»-методом, перенаправляющим «вызов» на элементы массива (в примере — print):

    > module com.lagoona.iterator {
    > …
    > class ArrayForwardIterator {
    > Any[] data;
    > method default() {
    > int j = 0;
    > while (j current => this.data [j ++];
    > }
    > }
    > }
    >
    > class Array {
    > Any[] data;
    > …
    > method ArrayForwardIterator forward () {
    > ArrayForwardIterator i =
    > new ArrayForwardIterator ();
    > i.data = this.data ;
    > return i ;
    > }
    > }
    >
    > class LagoonaIterator {
    > Array array ;
    > …
    > method void action () {
    > array.forward ().print ();
    > }
    > }
    > }

    Указывается на наличие «агрессивного» статического анализа в компиляторе для снижения необходимости в динамической диспетчеризации (видимо, лишь в простых случаях…).
    Решение не ограничивает в алгоритмике, что, вероятно, ключевое свойство…

    Ответить

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

      Про Лагуну не знал, и раз автор Michael Franz, то это точно интересно. Спасибо.

      Ответить

    2. Прочитал про Лагуну — интересный взгляд с другой стороны, полшага в сторону утиной типизации. Впрочем, весомость проблемы, которую они выставляют главной, на мой взгляд, несколько преувеличена.

      Она есть, но ёё можно решать разными способами, например, через extension functions (Swift, Kotlin) или через возможность «сборки» методов класса, о чем я рассказывал на конференции ИСП в 2019 года «OOP or not OOP or better OOP» или через «сборный разъем» на верстаке.

      Впрочем, «сборный разъем» — это снова заход с другой стороны, так как тут разные методы «сборного интерфейса» могут обращаются к разным объектам (аркам), а это потребует другой реализации.

      Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *