The ModulaTor logo 7KB

The ModulaTor

Oberon-2 and Modula-2 Technical Publication

Erlangen's First Independent Modula_2 Journal! Nr. 1/Feb-1993


The ModulaTor's Forum

Communication about Persistent Objects in Oberon-2

    7-Jan-93  8:58:00 (2nd ed., 12-Jan-1993)
Sb: O2: Persistent Objects
Fm: MAIL 
To: comp.lang.modula2 feed >INTERNET: info-m2@ucf1vm.bitnet

Oberon-2:

The chapter on Persistent Objects in the new book Objektorientierte Programmierung in Oberon-2, Springer Verlag, 1992 (OOPiO2) by H.P. M~ossenb~ock , inspired me to write a test program in Oberon-2 using ModulaWare's compiler H2O on AXP|VAX/OpenVMS.

When writing to file, the program retrieves the record type name information at run-time with the procedure Objects.ObjToName and writes the type names ("moduleName.typeName") together with the associated data of a heterogeneous list of objects to a file.

When reading the list from file, the type names stored in the file are used to reconstruct the original type with SYSTEM.NEW (p, n), where the pointer's type tag and size n are set their original values in Objects.NameToObj.

As M~ossenb~ock showed in his book, the advantage with persistant objects is that simply adding new methods to load and store any extension of the base class is all you need to support new data structures on the file. There is no need to modify the write-to or read-from-file procedure.

Does anybody know what Oberon-2 implementations support or provide facilities for ObjToName and NameToObj for arbitrary (non-anonymous) type names?

The C++ working group plans to make language provisions for run-time type information and persistent objects too. Al Stevens wrote an article in Dec-1992 issue of Dr. Dobb's Journal (pp 34..44) entitled Persistent Objects in C++. In this article he compares the possibilities in plain old C, which he claims to be not perfect with the C++ solution, which introduces a new set of problems...

In Oberon-2 this is possible now without any language extension.

Guenter

PS.: Thanks to my coworker Hartmut who extended the AXP|VAX/OpenVMS Oberon-2 compiler to store the type name information, size and tag. He also wrote the low-level module Objects for H2O. The design took him one day :-) I needed two days to debug his changes in the compiler's object-file generation module (OpenVMS linker interface) :-(

I'll list the source of Test_Objects (uses ISO M2 Std I/O Lib) in an upcoming issue of ModulaWare's "The ModulaTor" newsletter [ed. note: see below].

H.P. M~ossenb~ock's book OOPiO2 is also available in English.

Sender: thutt@MAIL.CASI.NASA.GOV
Date: Thu, 07 Jan 93 07:21:50 EST
From: thutt <thutt@MAIL.CASI.NASA.GOV>
To: 100023.2527@COMPUSERVE.COM

Subject: O2: Persistent Objects

Regarding your question about persistant objects, and Oberon-2 implementations that support it.

The basic answer is that any correctly functioning Oberon-2 system should be able to perform this task. The reason being that every record has a type descriptor, and stored within the type descriptor is the type name.

ETH technical document 156 describes, and shows, an implementation of the Files1 module by Josef Templ. This module provides support for the presistant objects, and describes in detail how it works. Recommended reading.

Files1 and Files have been merged into one module (according to ETH), so it will now be possible to perform persistant objects with stock Oberon implementations.

Isn't Oberon wonderful?

Taylor Hutt

Championing worldwide usage of Oberon-2!

    9-Jan-93  9:40:00
Subject: O2: Persistent Objects
To: thutt   >INTERNET:thutt@MAIL.CASI.NASA.GOV
Taylor,

Thanks for your reply. Since one year, I didn't get so many replies to a single technical posting.

>The basic answer is that any correctly functioning Oberon-2 system should be able to perform this task. The reason being that every record has a type descriptor, and stored within the type descriptor is the type name.<

That's true only for Oberon Systems but not for stand alone Oberon-2 compilers. Ours is stand alone under VAX/VMS and supports the run-time, source-level VMS-debugger and interfaces easily to all other native-code language compilers available under VMS.

Also I know of other [commercial] stand alone O2 compilers (Amiga, DOS, ...) that don't store the type names anywhere.

>ETH technical document 156 describes, and shows, and implementation of the Files1 module by Josef Templ. This module provides support for the presistant objects, and describes in detail how it works. Recommended reading.<

We implemented the facilities for persistent objects from the scratch. But it will be interesting to read how ETH did it. I'll try to get a copy of report 156 from ETH.

>Isn't Oberon wonderful?

I agree that the programming language Oberon-2 is wonderfull. I played around with the Oberon System (386) from ETH but I still didn't fell in love with the PC. Also I don't think that the current implementation of the Oberon System gets much respect from industry. If I were pessimistic I'd say that 95% of the work has still to be done to get a smart implementation under MS-DOS which then must also run under OS/2 2.0 and WNT in an MS-DOS window. But that's only one of the missing features that would improve acceptance. Our Jan-92 issue of The ModulaTor newsletter addresses ETH's Oberon/386 System from a user's point of view.

Concerning the Oberon System: I'll try to port the Oberon System written in Oberon[-1] and Oberon0 (a restricted and much smaller version of the Oberon System written in Oberon-2 and described in OOPiO2) under VAX/VMS using our Oberon-2 Compiler. But it will only be experimental.

Guenter

Sender: thutt@MAIL.CASI.NASA.GOV
Date: Mon, 11 Jan 93 07:54:18 EST
From: thutt <thutt@MAIL.CASI.NASA.GOV>
To: 100023.2527@CompuServe.COM

Subject: O2: Persistent Objects

[ed. note: when asked whether he would allow to publish his private reply to my public message in comp.lang.modula2 in the Forum's section of "The ModulaTor":]

Sure. I'll do anything to help people understand the actual potential of Oberon and the Oberon system.

As we have been working on duplicating an Oberon system for MS-DOS, we have become quite awe struck by the technical elegance of the Oberon system. The things that are working in concert together (internally) is a beautiful sight to behold. The adage 'Make it as simple as possible' surely holds in this system.

We've been working on an Oberon system for MS-DOS (I know, yuck...MS-DOS) and I am currently in the process of writing the operating system proper (I'm also the compiler person). Another person is writing the display driver, and a third is writing the disassembler. We wish to remain as close to 100% compatible with ETH as possible, but our display will probably be different (better, in our opinion). We will also probably only require a 2 button mouse.

The system is currently running in protected mode (on top of MS-DOS), and supports the amount of memory installed in the system. DPMI is required for operation of this system.

An interesting tribute to Oberon's abilities are the fact that the bootstrapping loader consists of about 5K of 386 assembly language (object code, not source) , and about 6K of Oberon produced object code (with debugging code in place, smaller with it removed).

The last major hurdle before the rest of the OS can be written is the GC routines. GC is about 95% working, and should be completed this week. The system is going to be a commercial system. Price will be cheap.

People intersted in another good Oberon for MS-DOS (Oberon-2, rather than the Oberon-1 of ETH) can write to me directly.

Taylor

Sender: thutt@MAIL.CASI.NASA.GOV
Date: Mon, 11 Jan 93 10:23:39 EST
From: thutt <thutt@MAIL.CASI.NASA.GOV>
To: 100023.2527@CompuServe.COM

Subject: Something I forgot to mention -- submission for newsletter

Here is something else you can print in the Modulator newsletter. I don't know where it originated, but I do know that it is used in the Oberon compiler from ETH. Speaking as a C programmer (prior to religious conversion to Oberon), this is not possible in C (due to the looseness of the % operator defintion).

If you must round a number to a multiple of some size, a simple and efficient way to do it is with an increment operator.

For example, let us suppose we must round to multiples of 13.

INC(variable, -variable MOD 13);

You can easily show that this will always replace 'variable' with a multiple of 13.

I've found this to come in handy in many places, and I hope it will come in handy for other people too.

Taylor

Championing worldwide usage of Oberon-2!

Module Types, the Oberon System's Persistent Objects Facility

Here is the definition of ETH-Zuerich's peristent objects' facility module Types, which was sent by Marc Brandis (ETH, Computer Systems Laboratory). Module Types is also available under POWERoberon for the IBM RISC System/6000. The definition is exactly the same on the Ceres, the DECstation and SPARCstation with the exception of 'Kernel.Module' being used instead of 'Modules.Module'.

The Oberon[-1] source code of module Modules is contained in the book Project Oberon by Wirth/Gutknecht.



DEFINITION Types;

  IMPORT SYSTEM, Modules;

  TYPE
    Type = POINTER TO TypeDesc;
    TypeDesc = RECORD
      name: ARRAY 32 OF CHAR;
      module: Modules.Module;
    END ;

  PROCEDURE BaseOf (t: Type; level: INTEGER): Type;
  PROCEDURE LevelOf (t: Type): INTEGER;
  PROCEDURE NewObj (VAR o: SYSTEM.PTR; t: Type);
  PROCEDURE This (mod: Modules.Module; name: ARRAY OF CHAR): Type;
  PROCEDURE TypeOf (o: SYSTEM.PTR): Type;

END Types.

Other references to Persistent Objects

Also the article about Mithril that appeared in Vol 2, Nr. 6 of The ModulaTor contained some remarks on persistent objects used in the design of a portable operating system/graphical user interface.

Persistent Objects in Oberon-2 on AXP|VAX/OpenVMS

by Hartmut Goebel and Guenter Dotzel, ModulaWare GmbH

Inspired by the chapter on persistent objects in the new book entitled Objektorientierte Programmierung in Oberon-2, Springer Verlag, 1992 (OOPiO2) by H.P. M~ossenb~ock, we implemented two facility modules for ModulaWare's AlphaAXP|VAX / OpenVMS Oberon-2 Compiler H2O called Object_Types and Objects. To illustrate the use of the generic procedures of Objects we also wrote an Oberon-2 example and test program for persistent objects.

Module Test_MyObjects creates a simple linked list of heterogeneous objects of the base class MyObj defined in module MyObjects.

MyObj's extension MyObj1 is defined in modules MyObjects1.

MyObj's extensions MyObj2 and MyObj3 are defined in modules MyObjects2.

Test_MyObjects then stores the objects' type-names with associated data on a binary file. The generic procedure Objects.WriteObj is used for that purpose. Since with the stand-alone Oberon-2 compiler for Alpha|VAX / OpenVMS there is no garbage collector, the list is then deleted from the heap (using dispose methods associated with each type).

After the binary data file is closed and re-opened, the objects are read from the file, their data type is determined and the linked list is generated again with objects' data values read from file by the generic procedure Objects.ReadObj. Then the data values and the structure of the list are checked.

Concerning the structure of the binary file, only the first occurrence of a module or type-name is written to the file. Subsequent references to this type use a type-index generated by the Objects.WriteString and Objects.ReadString methods. This mechanism is not visible to the clients of Objects.(WriteObj, ReadObj).

Test_MyObjects together with MyObjects* and Objects serve several other purposes:

0. Illustrate the handling of persistent objects with generic load/store procedures and up-calls.

1. Test the Oberon-2 compiler and run-time system implementation on AXP|VAX / OpenVMS: import and export of objects, record extension, pointer handling, list processing, storage allocation, dynamic type test, type guard, method call, string-copy and string-compare, single and multi-dimensional dynamic array.

2. Test the ISO Modula-2 Standard Library: for writing and reading binary files (RawIO), storage deallocation (Storage).

3. Test the implementation of module Objects, which provides the persistent objects facilities in close cooperation with the compiler's back-end. The definition module is listed below.

Type Tests in Oberon-2

Type tests in Oberon-2 are allowed not only in expressions but also as variable designator. This means a pointer type test can be perforemed when substituted as actual parameter in a procedure where the corresponding formal parameter is a variable parameter. (By the way, did you know that this is also possible with SYSTEM.VAL (T, variable_designator)?)

Example for pointer type test: If p is a pointer to a base type of T, p(T) could be substituted as actual parameter in NEW(p(T)) to get storage and type tag for type T allocated for p. But in this case a temporary variable pt of type T is needed (see procedure Test_MyObjects.GenList below):



  TYPE S=RECORD END;
    T=RECORD (S) ... END;

  VAR p: POINTER TO S; pt:= POINTER TO T;
  ...
    NEW(pt); p:=pt;

Although the construct NEW(p(T)) would be accepted by the compiler, the type test

generated by the compiler before calling NEW produces an access violation (NIL-pointer reference) at run-time, because NIL doesn't have a type tag.

Note, that other implementations may differ in this respect. AO (AmigaOberon V3) implementation of Oberon-2 for Commodore Amiga for example has the following rational: Because the value NIL is compatible with every pointer type the type-test will not fail for p=NIL. AO passes the type-test and in case of p=NIL; NIL(p(T)), allocates storage for T and sets the dynamic type to T.

Here is the order of text modules included in this article: Test_MyObjects.MOD, terminal log when run hex-dump of binary data file test_object.dat_lis, Objects.DEF, MyObjects.MOD, MyObjects1.MOD, MyObjects2.MOD, Objects_Types.DEF, and Objects.MOD. For I/O we use the ISO Modula-2 Standard Library. Their definitions for Oberon-2 are listed in Vol. 2, Nr. 8 (Sep-92 issue) of The ModulaTor.




MODULE Test_MyObjects;
(* Demonstrate heterogeneous list of persistent objects 
   (symetric store and load) in Oberon-2; see OOPiO2 p104..107. 
   Written by hG and GD/23-Dec-1992, revised 13-Jan-1992.
*)
IMPORT
  Objects,
  MO := MyObjects, M1 := MyObjects1, M2 := MyObjects2,
  File := StreamFile, ST := STextIO;

TYPE INTEGER = MO.INTEGER;

CONST
  maxDataRecords=20;
  fileName="test_object.dat_lis";

VAR
  i: INTEGER;
  result: File.OpenResults;
  r: Objects.Stream;
  h,x: MO.MyObj;

PROCEDURE GenList;
VAR 
  i: INTEGER; 
  m1: M1.MyObj1; m2: M2.MyObj2; m3: M2.MyObj3;
BEGIN (* generate heterogeneous list *)
  NEW(h); h.link := NIL;
  x:=h;
  FOR i:=0 TO maxDataRecords-1 DO
    CASE i MOD 3 OF
      0: NEW(m1); x.link := m1; |
      1: NEW(m2); x.link := m2; |
      2: NEW(m3); x.link := m3; |
    END;
    x.link.Data (i, FALSE); (* fill data *)
    x:=x.link; x.link:=NIL;
    ST.WriteChar(".");
  END;
END GenList;

BEGIN
  ST.WriteString("Generate list:"); ST.WriteLn;
  GenList;

  ST.WriteLn; ST.WriteString("Write list to file:"); ST.WriteLn;
  Objects.InitStream(r);
  File.Open(r.file, fileName, File.write + File.raw, result);
  MO.Check(result=File.opened);

  MO.WriteList(r, h);
  File.Close(r.file);
  MO.DisposeList(h);

  ST.WriteLn; ST.WriteString("Read list from file:"); ST.WriteLn;
  Objects.InitStream(r);
  File.Open(r.file, fileName, File.read + File.raw, result);
  MO.Check(result=File.opened);
  MO.ReadList(r, h);
  File.Close(r.file);

  ST.WriteLn; ST.WriteString("Check list:"); ST.WriteLn;
  MO.Check (h IS MO.MyObj);
  x:=h.link;
  FOR i:=0 TO maxDataRecords-1 DO (* check heterogeneous list *)
    ST.WriteChar(".");
    CASE i MOD 3 OF
      0: MO.Check(x IS M1.MyObj1); |
      1: MO.Check(x IS M2.MyObj2); |
      2: MO.Check(x IS M2.MyObj3); |
    END;
    x.Data(i,TRUE); (* check data *)
    x:=x.link;
  END;
  MO.Check (x=NIL);

  ST.WriteLn; ST.WriteString("Display list from file:"); ST.WriteLn;
  MO.DisplayList(h);
  MO.DisposeList(h);
  ST.WriteLn;
END Test_MyObjects.


Generate list:
....................
Write list to file:
.....................
Read list from file:
.....................
Check list:
....................
Display list from file:
MyObjects.MyObjDesc, no data
MyObjects1.MyObj1Desc, data= 0
MyObjects2.MyObj2Desc, DIM( 1), data= 1
MyObjects2.MyObj3Desc, DIM( 1, 2), data=
 2 3
MyObjects1.MyObj1Desc, data= 3
MyObjects2.MyObj2Desc, DIM( 3), data= 4 5 6
MyObjects2.MyObj3Desc, DIM( 2, 3), data=
 5 6 7
 6 7 8
MyObjects1.MyObj1Desc, data= 6
MyObjects2.MyObj2Desc, DIM( 4), data= 7 8 9 10
MyObjects2.MyObj3Desc, DIM( 3, 5), data=
 8 9 10 11 12
 9 10 11 12 13
 10 11 12 13 14
MyObjects1.MyObj1Desc, data= 9
MyObjects2.MyObj2Desc, DIM( 6), data= 10 11 12 13 14 15
MyObjects2.MyObj3Desc, DIM( 4, 6), data=
 11 12 13 14 15 16
 12 13 14 15 16 17
 13 14 15 16 17 18
 14 15 16 17 18 19
MyObjects1.MyObj1Desc, data= 12
MyObjects2.MyObj2Desc, DIM( 7), data= 13 14 15 16 17 18 19
MyObjects2.MyObj3Desc, DIM( 5, 8), data=
 14 15 16 17 18 19 20 21
 15 16 17 18 19 20 21 22
 16 17 18 19 20 21 22 23
 17 18 19 20 21 22 23 24
 18 19 20 21 22 23 24 25
MyObjects1.MyObj1Desc, data= 15
MyObjects2.MyObj2Desc, DIM( 9), data= 16 17 18 19 20 21 22 23 24
MyObjects2.MyObj3Desc, DIM( 6, 9), data=
 17 18 19 20 21 22 23 24 25
 18 19 20 21 22 23 24 25 26
 19 20 21 22 23 24 25 26 27
 20 21 22 23 24 25 26 27 28
 21 22 23 24 25 26 27 28 29
 22 23 24 25 26 27 28 29 30
MyObjects1.MyObj1Desc, data= 18
MyObjects2.MyObj2Desc, DIM( 10), data= 19 20 21 22 23 24 25 26 27 28

Dump of file _DUB0:[000000.EDISON.OBERON2]TEST_OBJECT.DAT_LIS;41 on 14-JAN-1993 11:08:11.63 File ID (22726,20,0) End of file block 3 / Allocated 3 Virtual block number 1 (00000001), 512 (0200) bytes 00000000 00000000 00000000 00000000 00000073 7463656A 624F794D 00000001 ....MyObjects................... 000000 00000000 00000000 00000000 00000063 7365446A 624F794D 00000002 00000000 ........MyObjDesc............... 000020 00000000 00000000 00003173 7463656A 624F794D 00000003 00000000 00000000 ............MyObjects1.......... 000040 00000000 00006373 6544316A 624F794D 00000004 00000000 00000000 00000000 ................MyObj1Desc...... 000060 7463656A 624F794D 00000005 00000000 00000000 00000000 00000000 00000000 ........................MyObject 000080 624F794D 00000006 00000000 00000000 00000000 00000000 00000000 00003273 s2..........................MyOb 0000A0 00000001 00000000 00000000 00000000 00000000 00000000 00006373 6544326A j2Desc.......................... 0000C0 00000000 00000000 00006373 6544336A 624F794D 00000007 00000005 00000001 ............MyObj3Desc.......... 0000E0 00000003 00000003 00000002 00000002 00000001 00000000 00000000 00000000 ................................ 000100 00000006 00000005 00000004 00000003 00000006 00000005 00000003 00000004 ................................ 000120 00000006 00000007 00000006 00000005 00000003 00000002 00000007 00000005 ................................ 000140 00000004 00000006 00000005 00000006 00000004 00000003 00000008 00000007 ................................ 000160 00000005 00000003 00000007 00000005 0000000A 00000009 00000008 00000007 ................................ 000180 0000000B 0000000A 00000009 0000000C 0000000B 0000000A 00000009 00000008 ................................ 0001A0 00000003 0000000E 0000000D 0000000C 0000000B 0000000A 0000000D 0000000C ................................ 0001C0 0000000C 0000000B 0000000A 00000006 00000006 00000005 00000009 00000004 ................................ 0001E0 Dump of file _DUB0:[000000.EDISON.OBERON2]TEST_OBJECT.DAT_LIS;41 on 14-JAN-1993 11:08:11.63 File ID (22726,20,0) End of file block 3 / Allocated 3 Virtual block number 2 (00000002), 512 (0200) bytes 0000000B 00000006 00000004 00000007 00000005 0000000F 0000000E 0000000D ................................ 000000 0000000E 0000000D 0000000C 00000010 0000000F 0000000E 0000000D 0000000C ................................ 000020 00000011 00000010 0000000F 0000000E 0000000D 00000011 00000010 0000000F ................................ 000040 00000003 00000013 00000012 00000011 00000010 0000000F 0000000E 00000012 ................................ 000060 0000000F 0000000E 0000000D 00000007 00000006 00000005 0000000C 00000004 ................................ 000080 00000008 00000005 00000007 00000005 00000013 00000012 00000011 00000010 ................................ 0000A0 00000015 00000014 00000013 00000012 00000011 00000010 0000000F 0000000E ................................ 0000C0 00000016 00000015 00000014 00000013 00000012 00000011 00000010 0000000F ................................ 0000E0 00000017 00000016 00000015 00000014 00000013 00000012 00000011 00000010 ................................ 000100 00000018 00000017 00000016 00000015 00000014 00000013 00000012 00000011 ................................ 000120 00000019 00000018 00000017 00000016 00000015 00000014 00000013 00000012 ................................ 000140 00000011 00000010 00000009 00000006 00000005 0000000F 00000004 00000003 ................................ 000160 00000005 00000018 00000017 00000016 00000015 00000014 00000013 00000012 ................................ 000180 00000015 00000014 00000013 00000012 00000011 00000009 00000006 00000007 ................................ 0001A0 00000015 00000014 00000013 00000012 00000019 00000018 00000017 00000016 ................................ 0001C0 00000015 00000014 00000013 0000001A 00000019 00000018 00000017 00000016 ................................ 0001E0 Dump of file _DUB0:[000000.EDISON.OBERON2]TEST_OBJECT.DAT_LIS;41 on 14-JAN-1993 11:08:11.63 File ID (22726,20,0) End of file block 3 / Allocated 3 Virtual block number 3 (00000003), 512 (0200) bytes 00000015 00000014 0000001B 0000001A 00000019 00000018 00000017 00000016 ................................ 000000 00000015 0000001C 0000001B 0000001A 00000019 00000018 00000017 00000016 ................................ 000020 0000001D 0000001C 0000001B 0000001A 00000019 00000018 00000017 00000016 ................................ 000040 0000001D 0000001C 0000001B 0000001A 00000019 00000018 00000017 00000016 ................................ 000060 00000013 0000000A 00000006 00000005 00000012 00000004 00000003 0000001E ................................ 000080 0000001B 0000001A 00000019 00000018 00000017 00000016 00000015 00000014 ................................ 0000A0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000001C ................................ 0000C0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 0000E0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 000100 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 000120 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 000140 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 000160 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 000180 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 0001A0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 0001C0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ................................ 0001E0


DEFINITION Objects; IMPORT A2OLayout, Files; CONST maxIdentLen = 32; TYPE ModuleTypeName = RECORD module, type: A2OLayout.Name; END ; Object = POINTER TO ObjectDesc; ObjectDesc = RECORD PROCEDURE (o: Object) Load (VAR stream: Stream); PROCEDURE (o: Object) Store (VAR stream: Stream); END ; Stream = RECORD (Files.Rider) PROCEDURE (VAR r: Stream) ReadString (VAR s: A2OLayout.Name); PROCEDURE (VAR r: Stream) WriteString (s: A2OLayout.Name); END ; TypeName = A2OLayout.Name; PROCEDURE CopyObj (orig: Object; VAR copy: Object); PROCEDURE DisposeObj (VAR o: Object); PROCEDURE InitStream (VAR r: Stream); PROCEDURE NameToObj (name: ModuleTypeName; VAR o: Object); PROCEDURE ObjToName (o: Object; VAR name: ModuleTypeName); PROCEDURE ReadObj (VAR r: Stream; VAR x: Object); PROCEDURE WriteObj (VAR r: Stream; x: Object); END Objects.


MODULE MyObjects; IMPORT Objects, File := StreamFile, ST := STextIO; TYPE INTEGER* = Objects.INTEGER; TYPE MyObj * = POINTER TO MyObjDesc; MyObjDesc * = RECORD (Objects.ObjectDesc) link * : MyObj; END; (* -- support functions -- *) PROCEDURE Check * (b: BOOLEAN); BEGIN IF ~ b THEN HALT(99); END; END Check; (* -- MyObj methods -- *) PROCEDURE (o: MyObj) Load * (VAR stream: Objects.Stream); (* no data to load *) END Load; PROCEDURE (o: MyObj) Store * (VAR stream: Objects.Stream); (* no data to store *) END Store; PROCEDURE (o: MyObj) Data * (i: INTEGER; check: BOOLEAN); BEGIN (* no data to fill/check *) END Data; PROCEDURE (o: MyObj) Display *; BEGIN ST.WriteString(', no data'); END Display; PROCEDURE DisplayObj (x: MyObj); VAR name: Objects.ModuleTypeName; BEGIN Objects.ObjToName(x,name); (*ST.WriteString('TypeName=');*) ST.WriteString(name.module); ST.WriteChar ("."); ST.WriteString(name.type); x.Display; ST.WriteLn; END DisplayObj; PROCEDURE (x: MyObj) Dispose *; END Dispose; (* -- operations on linked list of MyObj -- *) PROCEDURE DisposeList * (start: MyObj); (* there is currently no garbage collector in A2O|H2O (Oberon-2 under AXP|VAX/VMS) *) VAR y: MyObj; o: Objects.Object; BEGIN WHILE start#NIL DO y:=start.link; start.Dispose; o:=start; Objects.DisposeObj(o); start:=y; END; END DisposeList; PROCEDURE WriteList * (VAR r: Objects.Stream; start: MyObj); BEGIN WHILE start#NIL DO (* write list to file *) Objects.WriteObj(r, start); ST.WriteChar("."); start:=start.link; END; Objects.WriteObj(r, NIL); END WriteList; PROCEDURE ReadList * (VAR stream: Objects.Stream; VAR head: MyObj); VAR x: MyObj; y: Objects.Object; BEGIN Objects.ReadObj(stream, y); IF y # NIL THEN x := y(MyObj); head :=x ELSE x:=NIL END; WHILE x#NIL DO (* read list from file *) Objects.ReadObj(stream, y); ST.WriteChar("."); IF y # NIL THEN x.link := y(MyObj) ELSE x.link := NIL END; x:=x.link; END; END ReadList; PROCEDURE DisplayList * (start: MyObj); BEGIN WHILE start#NIL DO (* display list *) DisplayObj(start); start:=start.link; END; END DisplayList; END MyObjects.


MODULE MyObjects1; IMPORT Objects, MO := MyObjects, ST := STextIO, SW := SWholeLIO, RawIO; TYPE INTEGER = MO.INTEGER; MyObj1 * = POINTER TO MyObj1Desc; MyObj1Desc = RECORD (MO.MyObjDesc) data: INTEGER; END; PROCEDURE (o: MyObj1) Load * (VAR stream: Objects.Stream); BEGIN RawIO.Read(stream.file, o.data) END Load; PROCEDURE (o: MyObj1) Store * (VAR stream: Objects.Stream); BEGIN RawIO.Write(stream.file, o.data) END Store; PROCEDURE (o: MyObj1) Data * (i: INTEGER; check: BOOLEAN); BEGIN IF ~ check THEN o.data := i; ELSE MO.Check(o.data = i); END; END Data; PROCEDURE (o: MyObj1) Display *; BEGIN ST.WriteString(', data='); SW.WriteInt(o.data,0) END Display; END MyObjects1.


MODULE MyObjects2; IMPORT Objects, Objects_Types, MO := MyObjects, ST := STextIO, SW := SWholeLIO, RawIO; TYPE INTEGER = MO.INTEGER; ArrayElem = INTEGER; MyObj2 * = POINTER TO MyObj2Desc; MyObj2Desc = RECORD (MO.MyObjDesc) data: POINTER TO ARRAY OF ArrayElem; END; MyObj3 * = POINTER TO MyObj3Desc; MyObj3Desc = RECORD (MO.MyObjDesc) data: POINTER TO ARRAY OF ARRAY OF ArrayElem; END; PROCEDURE (o: MyObj2) Load * (VAR stream: Objects.Stream); VAR i, n, t: INTEGER; BEGIN RawIO.Read(stream.file, n); NEW(o.data, n); FOR i:= 0 TO LEN(o.data^)(**=n**) -1 DO RawIO.Read(stream.file, o.data[i]); END; END Load; PROCEDURE (o: MyObj3) Load * (VAR stream: Objects.Stream); VAR i,j, n0,n1: INTEGER; BEGIN RawIO.Read(stream.file, n0); RawIO.Read(stream.file, n1); NEW(o.data, n0, n1); FOR i:= 0 TO LEN(o.data^,0)(**=n0**) -1 DO FOR j:= 0 TO LEN(o.data^,1)(**=n1**) -1 DO RawIO.Read(stream.file, o.data[i,j]); END; END; END Load; PROCEDURE (o: MyObj2) Store * (VAR stream: Objects.Stream); VAR i, n: INTEGER; BEGIN n:=LEN(o.data^); RawIO.Write(stream.file, n); FOR i:= 0 TO n-1 DO RawIO.Write(stream.file, o.data[i]); END; END Store; PROCEDURE (o: MyObj3) Store * (VAR stream: Objects.Stream); VAR i,j, n0,n1: INTEGER; BEGIN n0:=LEN(o.data^); n1:=LEN(o.data^,1); RawIO.Write(stream.file, n0); RawIO.Write(stream.file, n1); FOR i:= 0 TO n0 -1 DO FOR j:= 0 TO n1 -1 DO RawIO.Write(stream.file, o.data[i,j]); END; END; END Store; PROCEDURE (o: MyObj2) Data * (i: INTEGER; check: BOOLEAN); VAR j: INTEGER; BEGIN IF ~ check THEN NEW(o.data, i DIV 2 +1); FOR j:=0 TO i DIV 2 DO o.data[j]:=i+j; END; ELSE MO.Check(LEN(o.data^,0) = i DIV 2 +1); FOR j:=0 TO i DIV 2 DO MO.Check(o.data[j]=i+j); END; END; END Data; PROCEDURE (o: MyObj3) Data * (i: INTEGER; check: BOOLEAN); VAR j,k: INTEGER; BEGIN IF ~ check THEN NEW(o.data, i DIV 3 +1, i DIV 2 +1); FOR j:=0 TO i DIV 3 DO FOR k:=0 TO i DIV 2 DO o.data[j,k]:=i+j+k; END; END; ELSE MO.Check((LEN(o.data^,0) = i DIV 3 +1) & (LEN(o.data^,1) = i DIV 2 +1)); FOR j:=0 TO i DIV 3 DO FOR k:=0 TO i DIV 2 DO MO.Check(o.data[j,k] = i+j+k); END; END; END; END Data; PROCEDURE (o: MyObj2) Display *; VAR i, n: INTEGER; BEGIN n:=LEN(o.data^); ST.WriteString(', DIM('); SW.WriteInt(n,0); ST.WriteString('), data='); FOR i:= 0 TO n-1 DO SW.WriteInt(o.data[i],0) END; END Display; PROCEDURE (o: MyObj3) Display *; VAR i,j, n0,n1: INTEGER; BEGIN n0:=LEN(o.data^); n1:=LEN(o.data^,1); ST.WriteString(', DIM('); SW.WriteInt(n0,0); ST.WriteChar(','); SW.WriteInt(n1,0); ST.WriteString('), data='); FOR i:= 0 TO n0 -1 DO ST.WriteLn; FOR j:= 0 TO n1 -1 DO SW.WriteInt(o.data[i,j],0); END; END; END Display; PROCEDURE (o: MyObj2) Dispose *; BEGIN Objects_Types.DisposeArray(o.data); END Dispose; PROCEDURE (o: MyObj3) Dispose *; BEGIN Objects_Types.DisposeArray(o.data); END Dispose; END MyObjects2.


DEFINITION Objects_Types; IMPORT SYSTEM; CONST QuadwordSize = 8; adrSize = 8; maxIdentLen = 32; tagSize = 8; TYPE ADDRESS_64 = SYSTEM.SIGNED_64; Name = ARRAY 32 OF CHAR; NamePtr = POINTER TO RECORD name: Name; END ; Object = POINTER TO ObjectDesc; ObjectDesc = RECORD END ; Size = SYSTEM.SIGNED_64; Tag = SYSTEM.SIGNED_64; Type = POINTER TO TypeDesc; TypeDesc = RECORD module: NamePtr; name: Name; END ; VAR Modules: ARRAY 256 OF ModEntryDesc; PROCEDURE DisposeDynArray (VAR o: SYSTEM.PTR; obolete1, obsolete2: LONGINT); PROCEDURE DisposeObj (VAR o: Object); PROCEDURE NewObj (VAR o: Object; t: Type); PROCEDURE SizeOf (o: Object): LONGINT; PROCEDURE StoreModObjects (typeDescBase: TypesArray); PROCEDURE This (module, name: ARRAY OF CHAR): Type; PROCEDURE TypeName (typ: Type; VAR module, name: ARRAY OF CHAR); PROCEDURE TypeOf (o: Object): Type; END Objects_Types.


MODULE Objects; (* H2O (VAX/VMS Oberon-2 Compiler) generic, symetric read/write (load/store) of peristent objects. See OOPiO2. Written by hG and G. Dotzel, ModulaWare GmbH, 23-Dec-1992, revised 13-Jan-1993. *) IMPORT IOChan, RawIO, OT := Objects_Types; CONST maxIdentLen * = OT.maxIdentLen; (* maximal length of Oberon-2 identifiers *) maxNames = 256; (* index compression for the first 256 names provided *) noName = ""; TYPE INTEGER* = LONGINT; Object * = POINTER TO ObjectDesc; ObjectDesc * = RECORD (OT.ObjectDesc) END; TypeName * = ARRAY maxIdentLen OF CHAR; ModuleTypeName * = RECORD module*, type*: TypeName; END; Stream * = RECORD file *: IOChan.ChanId; tab: ARRAY maxNames OF TypeName; (* tab[0]="" *) end: INTEGER (* tab[0..end-1] are filled *) END; PROCEDURE DisposeObj * (VAR o: Object); VAR oo: OT.Object; BEGIN oo:=o; OT.DisposeObj(oo); END DisposeObj; PROCEDURE (o: Object) Load * (VAR stream: Stream); (* abstract *) BEGIN HALT(20); END Load; PROCEDURE (o: Object) Store * (VAR stream: Stream); (* abstract *) BEGIN HALT(20); END Store; PROCEDURE ObjToName * (o: Object; VAR name: ModuleTypeName); VAR i: LONGINT; BEGIN (** (o # NIL) & (TypeOf(o) # NIL) **) OT.TypeName(OT.TypeOf(o),name.module,name.type); (** rest of the name.(module,type) is filled with CHR(0) **) END ObjToName; PROCEDURE NameToObj * (name: ModuleTypeName; VAR o: Object); VAR obj: OT.Object; BEGIN OT.NewObj(obj,OT.This(name.module,name.type)); IF obj=NIL THEN o:=NIL ELSE o := obj(Object) END; END NameToObj; PROCEDURE CopyObj * (orig: Object; VAR copy: Object); VAR obj: OT.Object; BEGIN OT.NewObj(obj,OT.TypeOf(orig)); copy := obj(Object); END CopyObj; (*---- Stream ----*) PROCEDURE InitStream * (VAR r: Stream); BEGIN r.tab[0]:=""; r.end:=1; END InitStream; PROCEDURE (VAR r: Stream) WriteString * (s: TypeName); VAR i: INTEGER; BEGIN i:=0; LOOP (* search s in r.tab *) IF i=r.end THEN (* first occurrence of s *) RawIO.Write(r.file, i); RawIO.Write(r.file,s); COPY(s, r.tab[r.end]); INC(r.end); EXIT ELSIF s=r.tab[i] THEN RawIO.Write(r.file, i); EXIT; ELSE INC(i); END; END; END WriteString; PROCEDURE (VAR r: Stream) ReadString * (VAR s: TypeName); VAR i: INTEGER; BEGIN RawIO.Read(r.file, i); IF i = r.end THEN (* full text follows *) RawIO.Read(r.file, s); COPY(s, r.tab[r.end]); INC(r.end); ELSE COPY(r.tab[i], s); END; END ReadString; PROCEDURE WriteObj * (VAR r: Stream; x: Object); VAR module,name: TypeName; BEGIN IF x=NIL THEN r.WriteString(noName); ELSE OT.TypeName(OT.TypeOf(x),module,name); r.WriteString(module); r.WriteString(name); x.Store(r); END; END WriteObj; PROCEDURE ReadObj * (VAR r: Stream; VAR x: Object); VAR module,name: TypeName; y: OT.Object; BEGIN r.ReadString(module); IF module="" THEN x:=NIL; ELSE r.ReadString(name); OT.NewObj(y,OT.This(module,name)); (* temporary variable y of base type and type test necessary. There is an error in OOPiO2 on p 106 *) x:=y(Object); x.Load(r); END; END ReadObj; END Objects.


IMPRESSUM: The ModulaTor is an unrefereed journal. Technical papers are to be taken as working papers and personal rather than organizational statements. Items are printed at the discretion of the Editor based upon his judgement on the interest and relevancy to the readership. Letters, announcements, and other items of professional interest are selected on the same basis. Office of publication: The Editor of The ModulaTor is Guenter Dotzel; he can be reached by tel/fax: [removed due to abuse] or by mailto:[email deleted due to spam]


Home Site_index Contact Legal Buy_products OpenVMS_compiler Alpha_Oberon_System DOS_compiler ModulaTor Bibliography Oberon[-2]_links Modula-2_links Amazon.com [3KB] [Any browser]


Webdesign by www.otolo.com/webworx, 26-Mar-1999