OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Суббота, 15 Май, 2021 16:49

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 9 ] 
Автор Сообщение
СообщениеДобавлено: Пятница, 16 Апрель, 2021 00:16 
Аватара пользователя

Зарегистрирован: Суббота, 16 Февраль, 2008 02:47
Сообщения: 478
Коллеги, в проекте Тайлер я использовал экспериментальный "параметризатор"; полагаю, он может быть полезен в более широком применении, и предлагаю вам статью и сам модуль. (Лонгрид). Текст статьи тж. включен в
Вложение:
Param.odc [30.06 КБ]
Скачиваний: 12
- там более привычное форматирование.

ПАРАМЕТРИЗАЦИЯ ПРОГРАММ
Условимся, что параметр - свойство или показатель объекта или системы, который можно измерить или задать для изменения характеристик или поведения.

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

Преимущество текстовых файлов - предельная простота настройки: нужен лишь текстовый редактор; реестровых систем - наличие библиотек для доступа и возможность организоывать деревья настроек.

Мы предлагаем критику сложившегося подхода и новый подход к параметризации программ.

1. Основной недостаток настроек - они далеки от задач, который решает программист. Чаще всего для решаемой задачи параметр - это значение переменной некоторого типа. Однако, чтобы получить это значение из источника настроек, программисту необходимо, кроме самой переменной, еще использовать ее строковый ключ, и задействовать преобразование из строки к типу переменной. Например, если в настройках хранится размер шрифта, то необходима переменная size: INTEGER, ключ "size" и преобразование Strings.StringToInt (и, вероятно, обработку ошибок)ю Впрочем, последнее может быть возложено на вспомогательные библиотеки.

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

3. Третий недостаток - они обычно привязывают программу к одному виду хранилища настроек: текстовому файлу, реестру ОС и т.д.

Мы предлагаем новый подход, основанный на записях. Записи Компонентного Паскаля, правила расширения типов и экспорта полей, вместе со средствами метапрограммирования, дают возможность:
    группировать настройки, используемые модулем (или по иному признаку: используемые видом или для такой-то задачи);
    использовать поля вместо отдельных переменных;
    использовать имена полей для обозначения настроек как в программе, так и в хранилище;
    использовать типы полей для автоматического преобразования типов (если в хранилище настройки хранятся в строках);
    использовать имя модуля и записного типа как естественные границы пространств имен настроек;
    полностью автоматизировать загрузку значений параметров из хранилища;
    использовать абстрактный интерфейс для параметризации, т.е. не привязывать программу к единственному виду хранилища;
    использовать параметризацию даже в отсутствие (плановом или аварийном) хранилища;
    программно задавать значения параметров по умолчанию;
    строить "отзывчивые" программы, безотлагательно реагирующие на изменения в хранилище;
    и - экспериментально - "параметризовать параметры" контекстом, в котором эти параметры запрашиваются.


ЗАДАЧА
Написать процедуру
PROCEDURE P (s: ARRAY OF CHAR);
которая будет предъявлять пользователю сообщение s. При этом текст сообщения определяется языком, заданным настройками; гарнитура и размер шрифта сообщения также определяются настройками. Для предъявления строки заданным шрифтом использовать процедуру WriteInFont (f: Fonts.Font; IN s: ARRAY OF CHAR).
(Заданную процедуру P можно назвать неявно параметризованной).



ОСНОВНЫЕ ПОНЯТИЯ
Объявим абстрактный базовый тип для всех параметров:
MODULE Params;...
TYPE Param* = POINTER TO ABSTRACT RECORD END;

Тогда для нашей задачи параметром будет:
MODULE Client;
TYPE Param* = POINTER TO RECORD (Params.Param)
typeface*: Fonts.Typeface;
size*: INTEGER;
lang*: ARRAY 2 OF CHAR
END;

VAR
param: Param;

Воспользоваться параметром предельно просто: он сформулирован в терминах, максимально приближенных к решаемой программистом задаче, и, кроме того, группирует параметризуемые величины, отделяя их структурно от прочих (глобальных) переменных.
MODULE Client;
PROCEDURE P (s: ARRAY OF CHAR);
BEGIN
Dialog.MapLangString(param.lang, s);
WriteInFont(Fonts.dir.This(param.typeface, param.size), s)
END P;

Чтобы запросить актуальное значение параметра, предназначена процедура
MODULE Params;...
PROCEDURE Refresh* (p: Param);

Таким образом, чтобы "загрузить" актуальное значение параметра, необходимо:
MODULE Client; ...
Params.Refresh(param);




ПАРАМЕТРИЧЕСКИЙ СПРАВОЧНИК
Откуда возьмутся значения в переменной param - т.е. фактическое значение параметра? За это отвечает абстрактный тип и переменная:
MODULE Params;...
TYPE Directory = POINTER TO ABSTRACT RECORD END;
VAR dir-: Directory;

Реализации параметрических справочников (Directory) могут черпать данные в привычных текстовых файлах, в реестровых системах, базах данных, удаленных хранилищах и т.д.; для проекта Тайлер мы сформулировали небольшой язык (синтаксис) для описания значений параметров и анализатор к нему. Язык максимально приближен к привычному для программиста синтаксису Компонентного паскаля. Например, приведенный выше параметр описывается так:
Client.Param = RECORD
typeface = "Syntax";
lang = "ru";
size = 12
END;

Справочник предоставляет типовую процедуру
MODULE Params;...
PROCEDURE (d: Directory) Fetch- (p: Param): Param, NEW, ABSTRACT;
(** Pre: p # NIL. Post: result # p; result # NIL => SYSTEM.TYP(p) = SYSTEM.TYP(result) *)
которая, определив фактический тип аргумента p, возвращает, если возможно, актуальное значение параметра этого типа, определенное в некоем источнике. Модуль Params гарантирует, что возвращенное процедурой Fetch значение не будет передано "третьим лицам" и останется иммутабельным; т.о. реализации справочников могут безопасно "раскрывать" модулю Params свои внутренние динамические переменные-параметры.

Разрабатываемые компоненты могут опираться на параметризацию; но приложения с этими компонентами могут поставляться без реализаций справочников (т.е. Params.dir = NIL); в этом случае параметры будут принимать начальные значения, заданные программно.



НАЧАЛЬНЫЕ ЗНАЧЕНИЯ И ГАРАНТИИ
Что если фактически оказывается, что справочник недоступен: удален текстовый файл или документ ББ с параметрами, или отсутствует связь с сервером? Что если параметр насчитывает множество полей, но хотелось бы позволить указывать (в текстовом документе) не все, полагаясь на значения по умолчанию? Для этого предусмотрена типовая процедура
MODULE Params;...
PROCEDURE (p: Param) InitDefaults*, NEW, ABSTRACT;

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

Иногда хочется, чтобы параметр удовлетворял неким инвариантам. Так, в примере выше на размер шрифта могут быть наложены ограничения: от 10 до 16. Чтобы гарантировать такие инварианты, предусмотрена типовая процедура
MODULE Params;...
PROCEDURE (p: Param) Init*, NEW, ABSTRACT;
Справочник вызывает ее после того, как новое значение параметра получено из некоего хранилища (текста, файла, реестра - т.е. по сути от пользователя, не обремененного инвариантами) - или в любое другое время, когда нужно гарантировать инварианты в отношении параметра.



ОТЗЫВЧИВОСТЬ
Хотелось бы, чтобы параметры были "отзывчивыми": когда в справочнике меняется значение параметра, программа незамедлительно откликается и подстраивает свое поведение. Этого можно добиться, получая актуальное значение параметра перед каждым использованием. Однако так можно сильно нагрузить ЭВМ, параметрический справочник станет "узким местом".

Чтобы этого избежать, предусмотрим поле .era и глобальную переменную era:
MODULE Params;...
TYPE Param = POINTER TO ABSTRACT RECORD
era-: INTEGER
END;

VAR era-: INTEGER

Тогда "экономичная" проверка параметра будет выглядеть так:
MODULE Client; ...
IF param.era # Params.era THEN Params.Refresh(param) END

Но этого недостаточно для полной "отзывчивости". Предположим, что Client.Param используется для реализации вида. При изменении параметра вид может пожелать перепроявить (перерисовать) себя. Чтобы уведомить вид об изменениях в справочнике параметров, предназначено сообщение
MODULE Params;...
TYPE UpdateMsg* = EXTENSIBLE RECORD (Views.Message) END;

Модуль Params рассылает это сообщение, когда меняются значения в справочнике параметров; заинтересованные виды, приняв его, обновляют собственные переменные-параметры с помощью Params.Refresh.

Реализация справочника уведомляет модуль Params об изменениях в справочнике посредством процедуры
MODULE Params;...
PROCEDURE IncEra*;



КОНТЕКСТУАЛИЗАЦИЯ ПАРАМЕТРОВ
И последнее экспериментальное средство. Хочется иметь возможность указывать отличные значения для одного и того же параметра, и дифференцировать их по некоему признаку. Конкретно: если вид В вставлен в вид Г, то хотелось бы, чтобы параметр П имел значение П1; а если вставлен в иной вид - то значение П2. Для решения этой задачи изменены интерфейсы процедур:
MODULE Params;...
PROCEDURE Refresh* (p: Param; f: Views.Frame);
PROCEDURE (d: Directory) Fetch- (p: Param; f; Views.Frame): Param, NEW, ABSTRACT;

Такой интерфейс позволяет реализации возвращать отличные значения параметра в зависимости от кадра f. При этом интерпретация f предоставлена реализациям; f может быть NIL. В параметрическом языке также есть оборот для задания отличных значений параметра:
Client.Param INSIDE Windows.Window = RECORD ... END;
Client.Param = RECORD ... END;



ЧТО ДАЛЬШЕ?
Внимательный читатель мог заметить, что в предложенном интерфейсе нет средств для сохранения параметра в справочнике. В проекте Тайлер в этом не было необходимости. Мы предлагаем сообществу высказать предложения, чтобы дополнить интерфейс Params средствами сохранения параметров в справочнике.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 16 Апрель, 2021 01:22 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1286
Откуда: Киев
adimetrius писал(а):
Мы предлагаем новый подход, основанный на записях
Хороший и правильный подход, но разве он новый? Или имеется ввиду новизна конкретного набора?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 16 Апрель, 2021 11:30 
Аватара пользователя

Зарегистрирован: Суббота, 16 Февраль, 2008 02:47
Сообщения: 478
Comdiv писал(а):
adimetrius писал(а):
Мы предлагаем новый подход, основанный на записях
Хороший и правильный подход, но разве он новый? Или имеется ввиду новизна конкретного набора?


А, да? Не новый?.. Ну лан, чож. А где почитать о предтечах?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 16 Апрель, 2021 14:54 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1286
Откуда: Киев
1. Это всё же вопрос, а не утверждение. Это уже Ваша задача сказать точней.
2. Точное название подхода не скажу, потому что проще изобретать всё заново, чем помнить все оттенки шаблонов проектирования :D. Предположу, что это ближе к Data access object


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 16 Апрель, 2021 17:32 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1455
Откуда: Украина, Киев
Как-то тоже возникла потребность в задании иерархичных структур или, как минимум, списков значений, в настройках. Применил возможность сериализации/десериализации, предоставляемую Delphi VCL. Универсально и просто, представление как является текстовым, так и представляет собой древовоидный реестр, одновременно.
Надо один раз сделать нормальную сериализацию/десериализацию, а не изобретать всякий раз велосипед.


Последний раз редактировалось Ярослав Романченко Пятница, 16 Апрель, 2021 17:43, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 16 Апрель, 2021 17:41 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1455
Откуда: Украина, Киев
Кстати, возвращаясь в русло Оберонов...
Неужели никто не в курсе, как хранились настройки в ETH Oberon?
Там свой формат хранения настроек в виде иерархичных Lisp-подобных структур со скобочками :)
Подсмотреть, адаптировать, улучшить и углубить :lol:


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 18 Апрель, 2021 18:55 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1587
Ярослав Романченко писал(а):
Кстати, возвращаясь в русло Оберонов...
Неужели никто не в курсе, как хранились настройки в ETH Oberon?
Там свой формат хранения настроек в виде иерархичных Lisp-подобных структур со скобочками :)
Подсмотреть, адаптировать, улучшить и углубить :lol:

Кстати, я, (почти) во всех своих проектах, подобный стиль и подход применяю. Оказался самым оптимальным, при описании "дерева" параметров.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 19 Апрель, 2021 10:38 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9409
Откуда: Россия, Орёл
Можно ещё трансформировать LISP-стиль под JSON-парсеры, используя JSON в режиме "только массивы".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 25 Апрель, 2021 00:40 
Аватара пользователя

Зарегистрирован: Четверг, 08 Октябрь, 2009 15:00
Сообщения: 3081
В ходе обсуждений с Антоном пришла идея мягко менять любую запись открытую для записи извне через Meta из текстовой базы данных. И лучше как-то уйти от наследования, чтобы такой инструмент был менее навязчивым. Ведь инициализировать параметры записей возможно и настроечными модулями.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 9 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2021, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB