home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 6 / FreshFish_September1994.bin / new / dev / obero / oberon-a / texts / oberon2.oop.text < prev    next >
Text File  |  1993-11-02  |  27KB  |  602 lines

  1. OBJECT-ORIENTED PROGRAMMING IN OBERON-2
  2.  
  3.  
  4. Hanspeter M„ssenb„ck
  5. ETH Z…rich, Institut f…r Computersysteme
  6.  
  7.  
  8. ABSTRACT
  9.  
  10. Oberon-2 is a refined version of Oberon developed at ETH. It introduces
  11. type-bound procedures, read-only export of data, and open array variables.
  12. The For statement is reintroduced. This paper concentrates on type-bound
  13. procedures which make Oberon-2 an object-oriented language with
  14. dynamically-bound messages and strong type checking at compile time.
  15. Messages can also be sent as data packets (extensible records) that are
  16. passed to a handler procedure and are interpreted at run time. This is as
  17. flexible as the Smalltalk message dispatching mechanism. Objects carry type
  18. information at run time which allows dynamic binding of messages, run time
  19. type tests, and the implementation of persistent objects. Oberon-2 is
  20. available on various machines.
  21.  
  22.  
  23. OVERVIEW
  24.  
  25. In 1987, Wirth defined the language Oberon [1]. Compared with its
  26. predecessor Modula-2, Oberon is smaller and cleaner, and it supports type
  27. extension which is a prerequisite for object-oriented programming. Type
  28. extension allows the programmer to extend an existing record type by adding
  29. new fields while preserving the compatibility between the old and the new
  30. type. Operations on a type, however, have to be implemented as ordinary
  31. procedures without syntactic relation to that type. They cannot be redefined
  32. for an extended type. Therefore dynamically-bound messages (which are vital
  33. for object-oriented programming) are not directly supported by Oberon,
  34. although they can be implemented via message records (see below).
  35.  
  36. Compared to Oberon, Oberon-2 [2] provides type-bound procedures (methods),
  37. read-only export of data, and open array variables. The For statement is
  38. reintroduced after having been eliminated in the step from Modula-2 to
  39. Oberon. This paper concentrates on type-bound procedures and the use of
  40. Oberon-2 for object-oriented programming. The other facilities are described
  41. in the Oberon-2 language report.
  42.  
  43. Type-bound procedures are operations applicable to variables of a record or
  44. pointer type. They are syntactically associated with that type and can
  45. therefore easily be identified as its operations. They can be redefined for
  46. an extended type and are invoked using dynamic binding. Type-bound
  47. procedures together with type extension make Oberon-2 a true object-oriented
  48. language with dynamically-bound messages and strong type checking at compile
  49. time. Oberon-2 is the result of three years experience of using Oberon and
  50. its experimental offspring Object Oberon [3]. Object-oriented concepts were
  51. integrated smoothly into Oberon without sacrificing the conceptual
  52. simplicity of the language.
  53.  
  54. Object-oriented programming is based on three concepts: data abstraction,
  55. type extension and dynamic binding of a message to the procedure that
  56. implements it. All these concepts are supported by Oberon-2. We first
  57. discuss type extension since this is perhaps the most important of the three
  58. notions, and then turn to type-bound procedures, which allow data
  59. abstraction and dynamic binding.
  60.  
  61.  
  62. TYPE EXTENSION
  63.  
  64. Type extension was introduced by Wirth in Oberon. It allows the programmer
  65. to derive a new type from an existing one by adding data fields to it.
  66. Consider the declarations
  67.  
  68.   TYPE
  69.     PointDesc  = RECORD x, y: INTEGER END;
  70.     PointDesc3D  = RECORD (PointDesc) z: INTEGER END;
  71.  
  72.     Point  = POINTER TO PointDesc;
  73.     Point3D  = POINTER TO PointDesc3D;
  74.  
  75.     PointXYZ  = POINTER TO PointDescXYZ;
  76.     PointDescXYZ  = RECORD x, y, z: INTEGER END;
  77.  
  78. PointDesc3D is an extension of PointDesc (specified by the type name in
  79. parentheses that follows the symbol RECORD). It starts with the same fields
  80. as PointDesc but contains an additional field z. Conversely, PointDesc is
  81. called the base type of PointDesc3D. The notion of type extension also
  82. applies to pointers. Point3D is an extension of Point and Point is the base
  83. type of Point3D. Type extension is also called inheritance because one can
  84. think of PointDesc3D as "inheriting" the fields x and y from PointDesc.
  85.  
  86. The crucial point about type extension is that Point3D is compatible with
  87. Point, while PointXYZ is not (though it also points to a record with the
  88. fields x and y). If p is of type Point and p3 is of type Point3D the
  89. assignment
  90.  
  91.   p := p3
  92.  
  93. is legal since p3 is an (extended) Point and therefore assignment compatible
  94. with p, which is a Point. The reverse assignment p3 := p is illegal since p
  95. is only a Point but not a Point3D like p3. The same compatibility rules
  96. apply to records.
  97.  
  98. Objects which are pointers or records have both a static type and a dynamic
  99. type. The static type is the type which the object is declared of. The
  100. dynamic type is the type which the object has at run time. It may be an
  101. extension of its static type. After the assignment p := p3 the dynamic type
  102. of p is Point3D, while its static type is still Point. That means that the
  103. field p3^.z is still part of the block that p points to, but it cannot be
  104. accessed via p since the static type of p does not contain a field p^.z
  105. (Figure 1).
  106.  
  107.  
  108.   Figure 1.  Assignment between the extended object and the base object
  109.  
  110. Objects like p are polymorphic, i.e. they may assume various types at run
  111. time. The actual type an object has at run time can be examined with a type
  112. test:
  113.  
  114.   p IS Point3D
  115.  
  116. yields TRUE if the dynamic type of p is Point3D (or an extension of it) and
  117. FALSE otherwise. A type guard
  118.  
  119.   p(Point3D)
  120.  
  121. asserts (i.e., tests at run time) that the dynamic type of p is Point3D (or
  122. an extension of it). If so, the designator p(Point3D) is regarded as having
  123. the static type Point3D. If not, the program is aborted. Type guards allow
  124. the treatment of p as a Point3D object. Therefore the following assignments
  125. are possible: p(Point3D)^.z := 0; p3 := p(Point3D);
  126.  
  127. For objects of a record type, the static and the dynamic types are usually
  128. the same. If pd is of type PointDesc and pd3 is of type PointDesc3D, the
  129. assignment pd := pd3 does not change the dynamic type of pd. Only the fields
  130. pd3.x and pd3.y are moved to pd, and the dynamic type of pd remains
  131. PointDesc. The compatibility between records is of minor importance except
  132. when pd is a formal variable parameter and pd3 is its corresponding actual
  133. parameter. In this case the dynamic type of pd is Point3D and the component
  134. pd3^.z is not stripped off.
  135.  
  136. The motivation for type extension is that an algorithm which works with type
  137. Point can also work with any of its extensions. For example, the procedure
  138.  
  139.   PROCEDURE Move (p: Point; dx, dy: INTEGER);
  140.   BEGIN INC(p.x, dx); INC(p.y, dy)
  141.   END Move;
  142.  
  143. can be called not only as Move(p, dx, dy) but also as Move(p3, dx, dy).
  144.  
  145.  
  146. TYPE-BOUND PROCEDURES
  147.  
  148. Type-bound procedures serve to implement abstract data types with
  149. dynamically bound operations. An abstract data type is a user-defined type
  150. which encapsulates private data together with a set of operations that can
  151. be used to manipulate this data. In Modula-2 or in Oberon an abstract data
  152. type is implemented as a record type and a set of procedures. The
  153. procedures, however, are syntactically unrelated to the record, which
  154. sometimes makes it hard to identify the data and the operations as an
  155. entity.
  156.  
  157. In Oberon-2, procedures can be connected to a data type explicitly. Such
  158. procedures are called type-bound. The interface of an abstract data type for
  159. texts may look like this:
  160.  
  161.   TYPE
  162.     Text = POINTER TO TextDesc;
  163.     TextDesc = RECORD
  164.       data: ... (*(hidden) text data*)
  165.       PROCEDURE (t: Text) Insert (string: ARRAY OF CHAR; pos: LONGINT);
  166.       PROCEDURE (t: Text) Delete (from, to: LONGINT);
  167.       PROCEDURE (t: Text) Length (): LONGINT;
  168.     END;
  169.  
  170. This gives a nice overview showing which operations can be applied to
  171. variables of type Text. However, it would be unwise to implement the
  172. operations directly within the record since that would clutter up the
  173. declarations with code. In fact, the above view of Text was extracted from
  174. the source code with a browser tool. The actual Oberon-2 program looks like
  175. this:
  176.  
  177.   TYPE
  178.     Text = POINTER TO TextDesc;
  179.     TextDesc = RECORD
  180.       data:  (*(hidden) text data*)
  181.     END;
  182.  
  183.   PROCEDURE (t: Text) Insert (string: ARRAY OF CHAR; pos: L