The ModulaTor logo 7KB

The ModulaTor

Oberon-2 and Modula-2 Technical Publication

Erlangen's First Independent Modula_2 Journal! Nr. 5/Jun-1993 
_____________________________________________________________

                                                                                                   
Submission for the First "Co-operative" Oberon-2 Standardisation Meeting, 
20/21-Jun-1993, London 


Oberon-2 Standardisation Proposal 

by Guenter Dotzel, 05-May-1993, 2nd ed. 06-May-1993 

The goal should be to standardise the Oberon-2 language and not the Oberon System. 
The Oberon-2 language should allow migration from and interoperability with other 
languages such as ISO Modula-2. 

 

1. Language 

To get the Oberon-2 Standard out as soon as possible no extensions (except for those 
mentioned in Chapter 3 below) should be made to the language defined by 
M~ossenb~ock's ETH-Report 160, revised May-1992. Since the Report 160 is not specific 
enough I propose to take the exact language semantics from Regis Crelier's OP2 
portable compiler front-end and to clarify all ambiguities of the language report. 

Although OP2 undergoes maintenance, it was rock-solid since end of 1991. Without OP2 
it is nearly impossible to implement an Oberon-2 compiler which is fully ETH-conformant. 

 

2. Library 

To avoid delays in standardising the library, the Oberon-2 Standard should adopt the full 
set of the ISO Modula-2 library (2nd CD). The few changes required to be able to define 
the Oberon-2 interface modules are documented in The ModulaTor, Sep-1992. This 
issue also contains the complete listing of the Oberon-2 interface modules for the ISO 
M2 Std Lib, except for module [Long]ComplexMath. 

To support the modules ComplexMath and LongComplexMath, ISO Modula-2's 
pervasive types COMPLEX and LONGCOMPLEX and ISO M2's pervasives procedures 
RE, IM and CMPLX could be provided through an additional library module Complex. 
[Ed. note/2nd ed.: The 1st ed. of this article proposed to declare COMPLEX and 
LONGCOMPLEX as record types and to export associated functions as well as type 
bound procedures. Later I found out that the complex data types must be known by (i.e.: 
built into) the compiler (see also 4.2 below) to be able to comply to the standard 
procedure calling conventions (at least on OpenVMS Alpha).] 

In our VAX/VMS Oberon-2 compiler project H2O, we've made good experiences in using 
the ISO M2 Std Lib in Oberon-2. 

 

2.1. Library extension: Persistent objects support 

Persistent objects should be supported by a required separate library module with the 
functionality of the module Objects_Types (see Apendix). A detailed description and 
discussion of persistent objects support is contained in The ModulaTor, Feb-1993 which 
is further illustrated in the OO-Extension proposal of ISO Modula-2 in The ModulaTor, 
May-1993. 

 

3. Extensions and clarifications 

Compile- and run-time semantics should be clarified. A comprehensive collection of 
ambiguities can be found in The ModulaTor, Apr-1993. 

Upward compatible extensions of Oberon-2 could be made later after the 
standardisation is finished or at least made substantial progress. 

Once, we've agreed not to extend the language in the first phase of standardisation 
process, there are only a few language changes required to clean-up the language, 
mainly in order to make it interoperable with the ISO Modula-2 language and library, 
namely 

3.1. allow structured function return values as in ISO Modula-2. This is required to be 
able to properly declare the library procedure RndFile.FilePos. 

3.2. allow underscores "_" anywhere in identifiers as in ISO Modula-2. 

3.3. for compatibility with any type, check-out whether the restriction to open array 
parameter of SYSTEM.BYTE being variable parameter could be dropped. 

3.4. SYSTEM.CAST should be introduced with the semantics of ISO Modula-2 (take 
minimal type length of both parameters) 

3.5. non-portable, processor-specific procedures in module SYSTEM (e.g.: 
SYSTEM.CC, BIT, LSH) should be eliminated. 

3.6. pervasive function procedure ASH should be renamed to SHIFT. Alternatively 
SHIFT could be placed in SYSTEM. 

3.7. introduce the additional pervasive procedure ASSERT(b: BOOLEAN) which is 
already contained in OP2. 

3.8. the different pervasive integer types SHORTINT and LONGINT should be renamed 
and put into module SYSTEM. For language interoperability with ISO Modula-2's 
enumeration and subrange types, integers with different size are still needed; Module 
SYSTEM should therefor export the integer types INTEGER_8, INTEGER_16, 
INTEGER_32, and INTEGER_64. The pervasive type INTEGER should have 
implementation defined size as in ISO Modula-2 (e.g. 32 Bit on a 32 Bit processor, 
identical to SYSTEM.INTEGER_32). 

3.9. there are some other minor unconveniences (such as SYSTEM.ADR() having 
LONGINT type) which should be discussed and cleaned-up by an ad-hoc 
SYSTEM-module working group. 

3.10. allow recursive procedure types as in ISO Modula-2 (required e.g. in library module 
ConvTypes). 

3.11. provide a parameter specification mechanism (syntax) for Oberon-2 interface 
modules to foreign languages (such as ISO Modula-2) to indicate that no type-descriptor 
is expected in case of variable parameter of record type. The symbol "-" could serve this 
purpose as parameter name suffix (if the symbol "-" is to be reserved for read-only 
parameters use the symbol "/"), e.g.: PROCEDURE p (VAR r-, s- : RecordType). 

 

4. Possible future language extensions 

The following extensions should to be considered after the standardisation is finished: 

4.1. remove the necessity for the "D"-scale factor in long real literals and introduce 
RR-real number literals as in ISO Modula-2. 

4.2. provide complex arithmetic support as in ISO M2: introduce new pervasive types 
COMPLEX and LONGCOMPLEX, new pervasive function procedures CMPLX, RE, and 
IM and allow the operators +, -, *, /, =, # and negation to be applied to complex type 
operands. 

4.3. introduce the additional pervasive function procedure LENGTH for strings with ISO 
Modula-2's semantic. 

4.4. in addition to ENTIER, introduce the additional pervasive function procedure INT 
with ISO Modula-2's semantic. 

4.5. introduce long sets to allow a set of CHAR or introduce the pervasive type 
LONGSET with MAX(LONGSET) equal to the number of bits of the largest pervasive 
type (i.e. LONGCOMPLEX) as in ISO Modula-2. 

4.6. optionally introduce additional integer operators "REM" and "IDIV" with the 
semantics of the ISO Modula-2 operators "REM" and "/" for integers. 

 

5. Possible future library extensions: 

The following extensions should to be considered after the standardisation of the 
Oberon-2 interface modules for the ISO M2 Std Lib is finished: 

5.1. provide explicit disposal of dynamic objects for implementation without garbage 
collector (see module Objects_Types below). 

5.2. Design an object-oriented library based on the structure of the ISO Modula-2 
Standard Library. 

 

6. References: 

Information how to get electronic edition of The ModulaTor is included in the impressum 
below. 

 

7. Appendix 

___________________________________________________________________

DEFINITION MODULE Objects_Types;
(* 
   Run-time type information to support persistent objects.
   Compiler supported object registration and
   and type-name processing.

   A2O|H2O (ModulaWare's AXP|VAX/VMS Oberon-2 Compiler Implementation)
   If preconditions specified are not fulfilled, HALT(20) is called.

   13-Jan-1993/hG/GD: designed based on ETH-Zuerich's module Type.
   05-Apr-1993/pF: procedures DisposeObj, Sizeof added.
   04-Nov-1994/hG/GD: procedure DisposeDynArray added.
*)
CONST maxIdentLen* = 32;

TYPE
  Object* = POINTER TO ObjectDesc;
  ObjectDesc* = RECORD END;

  Type* = POINTER TO TypeDesc;

PROCEDURE TypeOf * (o: Object): Type;
(* returns the dynmaic type of object o.
*)

PROCEDURE TypeName * (typ: Type; VAR module, name: ARRAY OF CHAR);
(* returns the source level module and record name of type t.
  module and name are filled from LENGTH() to LEN()-1 with CHR(0).
  Precondition: typ # NIL.
*)

PROCEDURE This * (module, name: ARRAY OF CHAR): Type;
(* If an object with the name "module.name" was registered,
  it returns the pointer type of "module.name"
  otherwise NIL is returned.
*)

PROCEDURE NewObj * (VAR o: Object; t: Type);
(* creates an object depending on the dynamic type of t.

  A2O|H2O implementation details:
  Allocation is performed by calling SYSTEM.NEW, which in
  H2O calls LIB$GET_VM. In A2O this is a call to Storage.ALLOCATE,
  which usually also calls the OpenVMS system library routine
  LIB$GET_VM.
  Precondition: t # NIL.
*)

PROCEDURE SizeOf * (o: Object) : LONGINT;
(* returns the number of bytes allocated to the dynamic type of the object o,
  not counting the size of the type tag which is equal to SIZE(SYSTEM.PTR).
  Precondition: o # NIL.
*)

PROCEDURE DisposeObj * (VAR o: Object);
(* disposes an object o pointing to any extension of Objects_Types.ObjectDesc
  depending on the dynamic type of o (including the storage occupied by the
  type tag). 
  A2O|H2O implementation detail:
  Deallocation is peformed by calling Storage.DEALLOCATE, which usually
  calls the OpenVMS system library routine LIB$FREE_VM. 
  Precondition: o # NIL, postcondition: o = NIL.
*)

PROCEDURE DisposeDynArray * (VAR o: SYSTEM.PTR;
  numDims, elemSize: LONGINT);
(* dispose a Oberon-2 dynamic array with numDims dimensions and elemSize
  element size. o is a pointer variable to a n-dimensional dymamic array
  such as VAR o: POINTER TO {ARRAY OF}_n T;
  DisposeDynArray(o, n, SIZE(T)); disposes the dynamic array o including
  its array descriptor.
  Precondition: o # NIL, postcondition: o = NIL
  In A2O, this procedure does not have the parameters numDims, elemSize;
  their values are known from the array descriptor. 
*)

PROCEDURE StoreModObjects * (typeDescBase, objects: SYSTEM.PTR);
(*
  A call to StoreModObjects is generated by the Oberon-2 compiler in
  module body of any Oberon-2 program to register the module's record types.
  Run-time type information can be processed with the procedures
  TypeOf, TypeName, This, Sizeof and DisposeObj for all objects which are an
  extension of type Object.

  H2O implementation detail:
  In H2O, the call is actually performed indirectly by the run-time procedure 
  mod$storemodobjects contained in MODRTS.mar (part of H2ORTS.OLB)
*)
END Objects_Types.

__________________________________________________________________

ModulaTor Forum

From    KH@ATHENS.CS.WAIKATO.AC.NZ
Realname: Keith Hopper 
To      G_DOTZEL
Subject OO--------ps!
Date    Fri, 04-30-93 at 04:54

Guenther, 

I read your e-mail version of the OO proposal [The ModulaTor [3, 4], May-1993] just now 
and I have a number of reservations which I thought I would share with you privately (just 
in case I am wrong!!) 

The separability of a class module definition from its implementation is not a problem 
provided that the class module is itself a new pervasive type. By this I mean that 
declaring 

     CLASS MODULE Widget ;

actually defines a new type directly accessible from the environment just like any other 
pervasive type (which don't actually have 'visible' definition modules of course), the 
name of the type being Widget. You may have seen the note I sent out yesterday to 
Albert [Wiedemann] which discussed this(?) [replY: no, I didn't! The information channels 
in the German WG13 subgroup are twisted roads] ). If you didn't, let me summarise it in 
relation to your notes, since we have been asked to conduct technical discussion on a 
one-to-one basis, rather than through the SC22WG13 list. 

The purpose of the class module is to provide the abstract data type as a first-class entity 
in the (extended) language. The beauty of this is that we merely need to extend the 
notion of declaration semantics to encompass the initialisation code of the defining type 
module implementation! The code for 'destruction' is likewise the finalisation code of that 
module -- so that NEW and DISPOSE just contain the declaration semantics in the same 
way. This is only a very minor change to the existing semantics -- with a major effect of 
course. 

This separability has the desired effect of retaining the 'flavour' of M-2. 

The introduction of polymorphism is, I suggest, also essential at this outer level (rather 
like the generic types in Ada). The matter is solved syntactically something after the style 
of a module protection expression 

     CLASS MODULE AVL [Element] ;

where the identifier 'Element' is a formal type parameter. I have not thought through all 
the implications of permitting multiple 'element' types, but I do not think it either 
necessary or desirable. 

Providing this kind of mechanism means that a polymorphic class type object declaration 
could be sean as one of the following 

     TYPE
          Filbert = RECORD
                         .
                         tree : POINTER TO AVL(CHAR) ;
                         .
                    END ;

     VAR
        Base_Tree
                  : AVL(REAL) ;

        Egbert
               : Filbert ;

        .
        .
        .
        WITH Egbert DO
            .
            NEW(tree) ;
            .
        END ;
         .

in which Base_Tree is an AVL of REAL which had initialisation code executed at the 
point when the declaration was elaborated -- Egbert.tree^ had its initialisation code 
executed at the point of the call of NEW. This clearly avoids the need for another 
'storage' module. 

As an aside, I proposed also that the promotion of class module types in our language 
extension led naturally to the thought that we should have the ability to provide 
procedures which could be used in an infix manner in expressions -- so that a procedure 
could be declared as, say, 

     INFIX PROCEDURE CONC(
                          Left : LIST
                          Right : Elem
                          ) : LIST

and later used as 

     Queue := Queue CONC Entry

or something similar. Thinking this one through and adding a touch of knowledge of 
Algol-68 enables us to contemplate defining the following 

CLASS MODULE STRING ;

     TYPE
         Index_Range = RECORD
                            from,
                            up_to_and_including : CSRDINAL
                       END ;

INFIX (3) PROCEDURE "+"(
                        Left,
                        Right : STRING
                        ) : STRING ;

INFIX (4) PROCEDURE "!"(
                        Target,
                        Pattern : STRING
                        ) : STRING ;      (* Tail after pattern - or empty *)

INFIX (2) PROCEDURE "<"(
                       First,
                       Second : STRING
                       ) : BOOLEAN ;

INFIX (4) PROCEDURE "?"(
                       Range : Index_Range ;
                       Target : String
                       ) : STRING ;       (* Extracted sub-string! *)

     etc.

END STRING.

in which the only new points are the specification of precedence and the use of string 
identifiers -- purely for definition purposes -- which introduces the identifier over-loading 
we have always wanted (I think!). 

This could also lead to the addition of BCD (which I know the DIN group are very 
interested in) in a similar fashion. 

The one other matter about which I am unhappy in your own suggestion is the 
'redefinition' problem. Here, again, I believe that there is a very simple elegant answer! At 
present if an identifier is explicitly imported then it may not be redeclared. Contemplate, 
however, the effect of an INHERIT clause whose semantics state that all identifiers 
imported will be re-exported -unless- they are redefined. In this case the following could 
happen for a module Garage, say, which had identifiers Fillup, Service, Wash and 
Polish. A new class module could be defined thus 

CLASS MODULE PitStop ;

     FROM Vehicles IMPORT
                          CAR ;

     INHERIT
          Garage ;

PROCEDURE Service(
               VAR  Client : CAR
                    ) ;
     .
     .
END PitStop.

in which case, assuming no other identifiers from Garage were redefined the original 
Garage.Fillup, Garage.Wash and Garage.Service would be available as PitStop.Fillup, 
etc (using the appropriate variable identifiers when using them of course -- eg 

MODULE GrandPrix ;

     IMPORT
          Vehicles,
          LIST,                (* Another polymorphic/generic class! *)
          STRING,
          PitStop ;

     TYPE
          Racing_Cars = Vehicles.CAR ;

          Entry = RECORD
                       vehicle : Racing_Cars ;
                       driver : STRING      (* Just his/her name! *)
                  END ;

     VAR
         Entries
                   : LIST(Entry) ;
     .
     .
     .
          Stands,
          Achterveld
                      : Pitstop ;

PROCEDURE Lap(
              Field : LIST
              ) : LIST ;

     VAR
          Current
                  : Entry ;
         .
         .
     BEGIN
          .
          .
          Current := NEXT(Field) ;

          IF ....... THEN
               Stands.Service(Current)
          END ;

          .
          .
          IF ...... THEN
               Achterveld.Service(Current)
          END ;

          .
          .
     END Lap ;
     .
     .
     .
END GrandPrix ;

I hope that this also gives the flavour of the kind of programming that you attempted to 
address without adding extra complication. 

In short, whether or not you approve of my infix suggestions which would simplify 
additional elementary type generation, I believe that the retention of separability (which 
is a key matter in my estimation which I would not accept compromising) is eased as is 
the use of the simple suggestions for inheritance (which -could- safely be multiple in my 
opinion) and the easy expression of polymorphism in the class module heading. 

In summary, we seem to agree on two of the additional tokens (CLASS and IS), have a 
different understanding of what a module could be -- but I believe that my suggestion of a 
class module being a type abstraction (as opposed to a state abstraction which is all we 
have at the moment) has advantages, and similar feelings about the semantics involved. 

Over to you! Feel free to pick at this, laugh at it (but please don't cry!) or pass it on to 
others in the DIN group as you will. 

Warmest regards, 

Keith 


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]
  ModulaWare home page   The ModulaTor download    [Any browser]

Webdesign by www.otolo.com/webworx, 14-Jul-1998