OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Суббота, 14 Июнь, 2025 03:30

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




Начать новую тему Ответить на тему  [ Сообщений: 10 ] 
Автор Сообщение
 Заголовок сообщения: Аналог конструктора для записи
СообщениеДобавлено: Четверг, 03 Август, 2023 07:16 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
Задача стояла следующим образом - сделать так, чтобы запись нельзя было создать никак иначе, кроме как через конструктор.
Для Оберона был сделан следующий простой пример.
Код:
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. Прошу извинить, если данная тема уже поднималась на форуме - не нашёл.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Четверг, 03 Август, 2023 08:59 

Зарегистрирован: Воскресенье, 25 Декабрь, 2022 23:14
Сообщения: 1556
вообще, в BBCB для производства объектов чаше используют фабрики. см. любой модуль, где есть `dir` — это фабрика (почему-то омики называют их Directory).

это не в смысле, что код неправильный, а в смысле что обычно подобные штуки нужны для расширяемых типов, и тогда базовый объявляется как ABSTRACT, и рядом с ним фабрика, тоже как абстракт. потом конкретные модули реализации подставляют фабрику, которая штампует нужное. в среде так сделаны платформо-независимые интерфейсы, куда хост-реализации подставляют своё.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Четверг, 03 Август, 2023 11:58 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
arisu писал(а):
вообще, в BBCB для производства объектов чаше используют фабрики. см. любой модуль, где есть `dir` — это фабрика (почему-то омики называют их Directory).

это не в смысле, что код неправильный, а в смысле что обычно подобные штуки нужны для расширяемых типов, и тогда базовый объявляется как ABSTRACT, и рядом с ним фабрика, тоже как абстракт. потом конкретные модули реализации подставляют фабрику, которая штампует нужное. в среде так сделаны платформо-независимые интерфейсы, куда хост-реализации подставляют своё.

Да, я вас понимаю, но реализовать абстрактный тип можно и без фабрики. Тут задача ставилась по-другому - реализация только через конструктор, без возможности использования оператора NEW в импортирующем модуле. Своего рода аналог классов в Delphi с обязательным Create.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Четверг, 03 Август, 2023 12:47 

Зарегистрирован: Воскресенье, 25 Декабрь, 2022 23:14
Сообщения: 1556
я так, для полноты картины. вдруг кто в тему нечаянно забредёт — пусть имеет информацию для размышления. ;-)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Суббота, 25 Январь, 2025 14:01 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
Можно сделать ещё такой вариант объекта с инициализатором
Код:
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.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Воскресенье, 26 Январь, 2025 23:52 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
AlexBogy писал(а):
Код:
c-:pa;
Что означает этот странный смайлик в коде?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Понедельник, 27 Январь, 2025 01:28 

Зарегистрирован: Пятница, 13 Март, 2015 16:40
Сообщения: 619
Александр Ильин писал(а):
AlexBogy писал(а):
Код:
c-:pa;
Что означает этот странный смайлик в коде?

"це" "минус" "двоеточие" "пэ" "а" "точка с запятой" - поле "це" с доступом "только читать" и типом "па".


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Понедельник, 27 Январь, 2025 15:10 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
Можно сделать вот такую абстрактную запись:
Код:
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).
Плюсом, в отличие от КП, является то, что для замены абстрактных методов не надо делать лишнее расширение.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Вторник, 28 Январь, 2025 19:59 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
Предлагаются вот такие аналоги записей в КП, которые можно реализовать на Оберон-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;


Есть только один подводный камень для реализации этого - необходимо зануление области памяти, выделяемой под запись.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Аналог конструктора для записи
СообщениеДобавлено: Четверг, 24 Апрель, 2025 20:02 

Зарегистрирован: Суббота, 30 Июль, 2022 12:02
Сообщения: 81
По дополнительному размышлению, вызванному прочтением топика 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.


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

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


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

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


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

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