Выше в примерчиках есть некое вольное манипулирование объектами. Напр., мы создали запись:
new(rec, [p1, p2]);
Затем можем, напр. случайно, обратиться к ней через некую проекцию, которая никак не "связана" с целевым типом-контейнером -- возникает ошибка доступа к памяти:
p3[rec] := 10;
Для статического разруливания подобных ситуаций в системе типизации (чтобы поддерживать марку "тотальности") известны два решения (ну, кроме по полной программе нафаршированных систем с зависимыми типами, со своими особенностями). Первое -- как в Scala -- Path-dependent Types, см. напр.:
https://danielwestheide.com/blog/2013/0 ... types.htmlОднако, здесь возникает "запаковка" типов в иные типы, что не очень-то удобно, тем более условный Pascal очень-таки "линейный" в объявлении и манипулировании типами.
Второе решение -- "регионы" как в Rust (решающие ряд задач, в т.ч. и иногда довольно-таки в мутной форме), доставшиеся ему от некоторых ML-вариациях через Cyclone (диалект С), что позволяет "разрывать" типы как угодно.
Можно воспользоваться предельно простой формой "регионов", заимствуя её у одной из вариаций Lustre (здесь на форуме есть тема про Esterel), решение для прикладников-инженеров (а не для любителей шаблонной магии С++).
Пусть регион есть некоторое виртуальное понятие связности (изначально техника возникла для решения задач управления памятью). Используется оператор "at" (или ключ. слово) при декларации элементов данных:
Код:
// Функция принимает ссылку на vector, которая помечена неким регионом "a".
// Результат функции есть новый объект типа iterator, этот объект
// также привязывается к этому же региону.
// Предварительное введение идентификатора-имени региона не требуется:
function find(in vec: vector at a; value: t): iterator at a;
begin
...
end;
...
// пометка полей (регион м.б. указан в любой части объявления)
type Rec = record
a at r: ref Obj;
b at r: ref Obj;
end;
Разметка регионами применяется и для переменных (в т.ч. привязка локальных переменных к параметрам процедур). Компилятор отслеживает корректность доступа. Побочное явление -- соблюдение совместимости области видимости, т.е. объекты должны быть в адекватном scope -- внутри параметров процедур, локализованы внутри одной записи и т.д. Без применения регионов для контроля необходимо в объектах иметь дополнительные ссылки на связанные элементы, и в runtime организовываются соответствующие проверки, и т.д.
Потребность явно применять регионы может возникать лишь для организации API, в остальном действует автоматический вывод.
Создание записи, в примере ранее, должно интерпретироваться компилятором так (предполагая, что универсальная операция new также оперирует регионами в зависимости от инициализируемых объектов):
Код:
var
rec: ref record at r;
p1: proj integer at r;
p2: proj string at r;
...
new(rec, [p1, p2]);