По дополнительному размышлению, вызванному прочтением топика
viewtopic.php?f=30&t=2987 (спасибо его автору Александру Ильину), и дополнительно упростив свои предыдущие варианты, получил следующее.
Для реализации абстрактных методов и процедур можно воспользоваться примером Александра Ильина:
Код:
MODULE abstract;
TYPE
tbp*=RECORD
END;
pp*=RECORD
pr*:PROCEDURE();
END;
PROCEDURE (VAR a:tbp) proc*();
BEGIN
HALT();
END proc;
BEGIN
END abstract.
В каждую заготовку абстрактного метода вставляется HALT(). Если метод возвращает значение, после HALT должен стоять фиктивный RETURN. С процедурными переменными будет аварийная остановка по обращению к указателю NIL. Для этого необходимо, чтобы компилятор занулял всю область памяти, занятую записью, что достаточно часто выполняется.
Достаточно легко реализуется запись с атрибутом LIMITED. Поскольку в импортирующем модуле ее нельзя создать ни как статическую переменную, ни как переменную динамическую (по указателю), а также её нельзя расширить, то нет смысла экспортировать тип, можно экспортировать переменную, которую, к тому же, можно заранее проинициализировать.
Код:
MODULE limited;
TYPE
pl=POINTER TO l;
l=RECORD
a*:LONGINT;
END;
VAR
p-:pl;
vl*:l;
PROCEDURE Init*();
BEGIN
NEW(p);
p^.a:=1;
END Init;
BEGIN
vl.a:=-1;
END limited.
Как видно, в О2 это реализуется без проблем. В оригинальном О можно экспортировать только статическую переменную, в О7 только указатель.
Нерасширяемая запись может реализовываться двумя путями - как экспорт типа-указателя и как экспорт записи, содержащей в себе запись, которая не должна быть расширена.
Код:
MODULE final;
TYPE
pf*=POINTER TO f;
f=RECORD
a*:LONGINT;
END;
exp*=RECORD
b*:f;
END;
BEGIN
END final.
Наконец, процедура, используемая только для реализации. Поскольку в импортирующем модуле ее нельзя вызвать напрямую, то нет смысла экспортировать ее как поле записи. Также, поскольку ее переопределение в импортирующем модуле не является обязательным, в экспортирующем модуле должна быть предусмотрена процедура по умолчанию.
Код:
MODULE readonly;
TYPE
prro=PROCEDURE(x:BOOLEAN):SHORTINT;
ro*=RECORD
pr:prro;
END;
PROCEDURE Default(x:BOOLEAN):SHORTINT;
BEGIN
CASE x OF
FALSE:RETURN 0;
ELSE RETURN -1;
END;
END Default;
PROCEDURE Init*(VAR a:ro;p:prro);
BEGIN
IF p=NIL THEN
a.pr:=Default;
ELSE
a.pr:=p;
END;
END Init;
PROCEDURE Run*(a:ro):SHORTINT;
BEGIN
IF a.pr=NIL THEN
a.pr:=Default;
END;
RETURN a.pr(TRUE);
END Run;
BEGIN
END readonly.
И если кому интересно, модуль для проверки таких типов записей.
Код:
<*+MAIN*>
MODULE record;
IMPORT st:=STextIO,sw:=SWholeIO,ma:=abstract,mf:=final,ml:=limited,mr:=readonly;
TYPE
tbp=RECORD(ma.tbp)
END;
VAR
rtbp:tbp;
rpp:ma.pp;
pf:mf.pf;
exp:mf.exp;
ro:mr.ro;
c:CHAR;
PROCEDURE procpp();
BEGIN
st.WriteString('Procedure variable');
st.WriteLn;
END procpp;
PROCEDURE (VAR a:tbp) proc();
BEGIN
st.WriteString('Type-bound procedure');
st.WriteLn;
END proc;
PROCEDURE New(x:BOOLEAN):SHORTINT;
BEGIN
CASE x OF
FALSE:RETURN 0;
ELSE RETURN 1;
END;
END New;
BEGIN
(* Проверка работы с абстрактными записями (идентификатор ABSTRACT) *)
st.WriteString('Checking work with abstract records');
st.WriteLn;
rtbp.proc();
rpp.pr:=procpp;
rpp.pr();
(* Проверка работы с нерасширяемыми записями (без идентификатора) *)
st.WriteString('Checking work with non-expandable records');
st.WriteLn;
NEW(pf);
pf^.a:=-1;
sw.WriteInt(pf^.a,0);
st.WriteLn;
exp.b.a:=1;
sw.WriteInt(exp.b.a,0);
st.WriteLn;
(* Проверка работы с ограниченными записями (идентификатор LIMITED) *)
st.WriteString('Checking work with limited records');
st.WriteLn;
ml.Init();
sw.WriteInt(ml.p^.a,0);
st.WriteLn;
sw.WriteInt(ml.vl.a,0);
st.WriteLn;
(* Метод read-only - только для имплементации *)
st.WriteString("Read-only method - for implementation only");
st.WriteLn;
sw.WriteInt(mr.Run(ro),0);
st.WriteLn;
mr.Init(ro,New);
sw.WriteInt(mr.Run(ro),0);
st.WriteLn;
st.WriteString('Press any key to end the program');
st.WriteLn;
st.ReadChar(c);
END record.