OberonCore https://forum.oberoncore.ru/ |
|
Аналог конструктора для записи https://forum.oberoncore.ru/viewtopic.php?f=30&t=6956 |
Страница 1 из 1 |
Автор: | AlexBogy [ Четверг, 03 Август, 2023 07:16 ] |
Заголовок сообщения: | Аналог конструктора для записи |
Задача стояла следующим образом - сделать так, чтобы запись нельзя было создать никак иначе, кроме как через конструктор. Для Оберона был сделан следующий простой пример. Код: MODULE Export; TYPE a=RECORD b-:INTEGER; END; VAR p-:POINTER TO a; PROCEDURE Init*(); BEGIN NEW(p); p^.b:=100; END Init; BEGIN END Export. Код: <*+MAIN*> MODULE Import; IMPORT STextIO,SWholeIO,Export; VAR c:CHAR; BEGIN Export.Init; SWholeIO.WriteInt(Export.p^.b,4); STextIO.WriteLn; STextIO.ReadChar(c); END Import. Иван Денисов сделал аналогичный пример на Компонентном Паскале Код: MODULE TestExport; TYPE Item*=POINTER TO LIMITED RECORD b-:INTEGER; END; PROCEDURE Init*():Item; VAR temp:Item; BEGIN NEW(temp); temp^.b:=100; RETURN temp; END Init; BEGIN END TestExport. Код: MODULE TestImport; IMPORT Log,TestExport; VAR Item:TestExport.Item; PROCEDURE Do*; BEGIN Item:=TestExport.Init(); Log.Int(Item^.b); Log.Ln; END Do; END TestImport. TestImport.Do P.S. Прошу извинить, если данная тема уже поднималась на форуме - не нашёл. |
Автор: | arisu [ Четверг, 03 Август, 2023 08:59 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
вообще, в BBCB для производства объектов чаше используют фабрики. см. любой модуль, где есть `dir` — это фабрика (почему-то омики называют их Directory). это не в смысле, что код неправильный, а в смысле что обычно подобные штуки нужны для расширяемых типов, и тогда базовый объявляется как ABSTRACT, и рядом с ним фабрика, тоже как абстракт. потом конкретные модули реализации подставляют фабрику, которая штампует нужное. в среде так сделаны платформо-независимые интерфейсы, куда хост-реализации подставляют своё. |
Автор: | AlexBogy [ Четверг, 03 Август, 2023 11:58 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
arisu писал(а): вообще, в BBCB для производства объектов чаше используют фабрики. см. любой модуль, где есть `dir` — это фабрика (почему-то омики называют их Directory). это не в смысле, что код неправильный, а в смысле что обычно подобные штуки нужны для расширяемых типов, и тогда базовый объявляется как ABSTRACT, и рядом с ним фабрика, тоже как абстракт. потом конкретные модули реализации подставляют фабрику, которая штампует нужное. в среде так сделаны платформо-независимые интерфейсы, куда хост-реализации подставляют своё. Да, я вас понимаю, но реализовать абстрактный тип можно и без фабрики. Тут задача ставилась по-другому - реализация только через конструктор, без возможности использования оператора NEW в импортирующем модуле. Своего рода аналог классов в Delphi с обязательным Create. |
Автор: | arisu [ Четверг, 03 Август, 2023 12:47 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
я так, для полноты картины. вдруг кто в тему нечаянно забредёт — пусть имеет информацию для размышления. ;-) |
Автор: | AlexBogy [ Суббота, 25 Январь, 2025 14:01 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
Можно сделать ещё такой вариант объекта с инициализатором Код: MODULE export; TYPE pa=POINTER TO a; a=RECORD b*:ARRAY 32 OF CHAR; END; exp*=RECORD c-:pa; END; PROCEDURE Init*(VAR x:exp); BEGIN NEW(x.c); x.c.b:="Hello, world!"; END Init; BEGIN END export. Код: <*+MAIN*>
MODULE test; IMPORT st:=STextIO,e:=export; VAR a:e.exp; b:CHAR; BEGIN e.Init(a); st.WriteString(a.c.b); st.WriteLn; st.ReadChar(b); END test. |
Автор: | Александр Ильин [ Воскресенье, 26 Январь, 2025 23:52 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
AlexBogy писал(а): Код: c-:pa; |
Автор: | Artyemov [ Понедельник, 27 Январь, 2025 01:28 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
Александр Ильин писал(а): AlexBogy писал(а): Код: c-:pa; "це" "минус" "двоеточие" "пэ" "а" "точка с запятой" - поле "це" с доступом "только читать" и типом "па". |
Автор: | AlexBogy [ Понедельник, 27 Январь, 2025 15:10 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
Можно сделать вот такую абстрактную запись: Код: MODULE Export; TYPE p_abs=POINTER TO abs; proc=PROCEDURE(x:p_abs;x:BOOLEAN):LONGINT; abs*=RECORD init:BOOLEAN; pr-:proc; END; PROCEDURE Init*(VAR x:abs;p:proc); BEGIN IF p#NIL THEN x.pr:=p; x.init:=TRUE; ELSE x.init:=FALSE; END; END Init; PROCEDURE Do*(x:abs); BEGIN ASSERT(x.init); END Do; BEGIN END Export. Ни одна процедура экспортирующего модуля без инициализации работать не будет (проверяется поле init). Плюсом, в отличие от КП, является то, что для замены абстрактных методов не надо делать лишнее расширение. |
Автор: | AlexBogy [ Вторник, 28 Январь, 2025 19:59 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
Предлагаются вот такие аналоги записей в КП, которые можно реализовать на Оберон-2 и Оберон-07. Код: TYPE (* Аналог записи ABSTRACT с процедурами ABSTRACT *) p_abstract=POINTER TO abstract; pr_abstract=PROCEDURE(x:p_abstract;x:BOOLEAN):LONGINT; abstract*=RECORD init:BOOLEAN; pr-:pr_abstract; END; (* Аналог нерасширяемой записи *) p_final*=POINTER TO final; final=RECORD a*:LONGINT; b*:CHAR; END; (* Аналог записи LIMITED *) p_limited=POINTER TO limited; limited=RECORD a*:CHAR; b*:BOOLEAN; END; export*=RECORD p-:p_limited; END; (* Аналог метода read-only - только для имплементации *) p_read=POINTER TO read; pr_read=PROCEDURE(p:p_read;x:BOOLEAN):LONGINT; read*=RECORD a*:BOOLEAN; pr:pr_read; END; PROCEDURE Init_abstract*(VAR x:abstract;p:pr_abstract); BEGIN IF p#NIL THEN x.pr:=p; x.init:=TRUE; ELSE x.init:=FALSE; END; END Init_abstract; PROCEDURE Run_abstract*(x:abstract); BEGIN ASSERT(x.init); END Run_abstract; PROCEDURE Do_read(x:p_read;y:BOOLEAN):LONGINT; BEGIN x^.a:=y; RETURN 1; END Do_read; PROCEDURE Init_read*(VAR x:read;p:pr_read); BEGIN IF p#NIL THEN x.pr:=p; ELSE x.pr:=Do_read; END; END Init_read; PROCEDURE Run_read*(x:read); BEGIN IF x.pr=NIL THEN x.pr:=Do_read; END; END Run_read; Есть только один подводный камень для реализации этого - необходимо зануление области памяти, выделяемой под запись. |
Автор: | AlexBogy [ Четверг, 24 Апрель, 2025 20:02 ] |
Заголовок сообщения: | Re: Аналог конструктора для записи |
По дополнительному размышлению, вызванному прочтением топика 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. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |