Advertisement
FreshProfiles2030

Untitled

Jan 19th, 2019
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 59.09 KB | None | 0 0
  1. From Modula to Oberon
  2.  
  3. N. Wirth
  4.  
  5. Abstract
  6.  
  7. The programming language Oberon is the result of a concentrated effort to
  8. increase the power of Modula-2 and simultaneously to reduce its complexity.
  9. Several features were eliminated, and a few were added in order to increase
  10. the expressive power and flexibility of the language. This paper describes
  11. and motivates the changes. The language is defined in a concise report.
  12.  
  13. Introduction
  14.  
  15. The programming language Oberon evolved from a project whose goal was the
  16. design of a modern, flexible, and efficient operating system for a
  17. single-user workstation. A principal guideline was to concentrate on
  18. properties that are genuinely essential and - as a consequence - to omit
  19. ephemeral issues. It is the best way to keep a system in hand, to make it
  20. understandable, explicable, reliable, and efficiently implementable.
  21.  
  22. Initially, it was planned to express the system in Modula-2 [1]
  23. (subsequently called Modula), as that language supports the notion of
  24. modular design quite effectively, and because an operating system has to be
  25. designed in terms of separately compilable parts with conscientiously
  26. chosen interfaces. In fact, an operating system should be no more than a
  27. set of basic modules, and the design of an application must be considered
  28. as a goal-oriented extension of that basic set: Programming is always
  29. extending a given system.
  30.  
  31. Whereas modern languages, such as Modula, support the notion of
  32. extensibility in the procedural realm, the notion is less well established
  33. in the domain of data types. In particular, Modula does not allow the
  34. definition of new data types as extensions of other, programmer-defined
  35. types in an adequate manner. An additional feature was called for, thereby
  36. giving rise to an extension of Modula.
  37.  
  38. The concept of the planned operating system also called for a highly
  39. dynamic, centralized storage management relying on the technique of garbage
  40. collection. Although Modula does not prevent the incorporation of a garbage
  41. collector in principle, its variant record feature constitutes a genuine
  42. obstacle. As the new facility for extending types would make the variant
  43. record feature superfluous, the removal of this stumbling block was a
  44. logical decision. This step, however, gave rise to a restriction (subset)
  45. of Modula.
  46.  
  47. It soon became clear that the rule to concentrate on the essential and to
  48. eliminate the inessential should not only be applied to the design of the
  49. new system, but equally stringently to the language in which the system is
  50. formulated. The application of the principle thus led from Modula to a new
  51. language. However, the adjective "new" has to be understood in proper
  52. context: Oberon evolved from Modula by very few additions and several
  53. subtractions. In relying on evolution rather than revolution we remain in
  54. the tradition of a long development that led from Algol to Pascal, then to
  55. Modula-2, and eventually to Oberon. The common traits of these languages
  56. are their procedural rather than functional model and the strict typing of
  57. data. Even more fundamental, perhaps, is the idea of abstraction: the
  58. language must be defined in terms of mathematical, abstract concepts
  59. without reference to any computing mechanism. Only if a language satisfies
  60. this criterion, can it be called "higher-level". No syntactic coating
  61. whatsoever can earn a language this attribute alone.
  62.  
  63. The definition of a language must be coherent and concise. This can only be
  64. achieved by a careful choice of the underlying abstractions and an
  65. appropriate structure combining them. The language manual must be
  66. reasonably short, avoiding the explanation of individual cases derivable
  67. from the general rules. The power of a formalism must not be measured by
  68. the length of its description. To the contrary, an overly lengthy
  69. definition is a sure symptom of inadequacy. In this respect, not complexity
  70. but simplicity must be the goal.
  71.  
  72. In spite of its brevity, a description must be complete. Completeness is to
  73. be achieved within the framework of the chosen abstractions. Limitations
  74. imposed by particular implementations do not belong to a language
  75. definition proper. Examples of such restrictions are the maximum values of
  76. numbers, rounding and truncation errors in arithmetic, and actions taken
  77. when a program violates the stated rules. It should not be necessary to
  78. supplement a language definition with a voluminous standards document to
  79. cover "unforeseen" cases.
  80.  
  81. But neither should a programming language be a mathematical theory only. It
  82. must be a practical tool. This imposes certain limits on the terseness of
  83. the formalism. Several features of Oberon are superfluous from a purely
  84. theoretical point of view. They are nevertheless retained for practical
  85. reasons, either for programmers' convenience or to allow for efficient code
  86. generation without the necessity of complex, "optimizing" pattern matching
  87. algorithms in compilers. Examples of such features are the presence of
  88. several forms of repetitive statements, and of standard procedures such as
  89. INC, DEC, and ODD. They complicate neither the language conceptually nor
  90. the compiler to any significant degree.
  91.  
  92. These underlying premises must be kept in mind when comparing Oberon with
  93. other languages. Neither the language nor its defining document reach the
  94. ideal; but Oberon approximates these goals much better than its
  95. predecessors.
  96.  
  97. A compiler for Oberon has been implemented for the NS32000 processor family
  98. and is embedded in the Oberon operating environment [8]. The compiler
  99. requires less than 50 KByte of memory, consists of 6 modules with a total
  100. of about 4000 lines of source code, and compiles itself in about 15 seconds
  101. on a workstation with a 25MHz NS32532 processor.
  102.  
  103. After extensive experience in programming with Oberon, a revision was
  104. defined and implemented. The differences between the two versions are
  105. summarised towards the end of the paper. Subsequently, we present a brief
  106. introduction to (revised) Oberon assuming familiarity with Modula (or
  107. Pascal), concentrating on the added features and listing the eliminated
  108. ones. In order to be able to start with a clean slate, the latter are taken
  109. first.
  110.  
  111. Features omitted from Modula
  112.  
  113. Data types
  114.  
  115. Variant records are eliminated, because they constitute a genuine
  116. difficulty for the implementation of a reliable storage management system
  117. based on automatic garbage collection. The functionality of variant records
  118. is preserved by the introduction of extensible data types.
  119.  
  120. Opaque types cater for the concept of abstract data type and information
  121. hiding. They are eliminated as such, because again the concept is covered
  122. by the new facility of extended record types.
  123.  
  124. Enumeration types appear to be a simple enough feature to be
  125. uncontroversial. However, they defy extensibility over module boundaries.
  126. Either a facility to extend given enumeration types has to be introduced,
  127. or they have to be dropped. A reason in favour of the latter, radical
  128. solution was the observation that in a growing number of programs the
  129. indiscriminate use of enumerations (and subranges) had led to a type
  130. explosion that contributed not to program clarity but rather to verbosity.
  131. In connection with import and export, enumerations give rise to the
  132. exceptional rule that the import of a type identifier also causes the
  133. (automatic) import of all associated constant identifiers. This exceptional
  134. rule defies conceptual simplicity and causes unpleasant problems for the
  135. implementor.
  136.  
  137. Subrange types were introduced in Pascal (and adopted in Modula) for two
  138. reasons: (1) to indicate that a variable accepts a limited range of values
  139. of the base type and to allow a compiler to generate appropriate guards for
  140. assignments, and (2) to allow a compiler to allocate the minimal storage
  141. space needed to store values of the indicated subrange. This appeared
  142. desirable in connection with packed records. Very few implementations have
  143. taken advantage of this space saving facility, because the additional
  144. compiler complexity is very considerable. Reason 1 alone, however, did not
  145. appear to provide sufficient justification to retain the subrange facility
  146. in Oberon.
  147.  
  148. With the absence of enumeration and subrange types, the general possibility
  149. of defining set types based on given element types appeared as redundant.
  150. Instead, a single, basic type SET is introduced, whose values are sets of
  151. integers from 0 to an implementation-defined maximum.
  152.  
  153. The basic type CARDINAL had been introduced in Modula in order to allow
  154. address arithmetic with values from 0 to 216 on 16-bit computers. With the
  155. prevalence of 32-bit addresses in modern processors, the need for unsigned
  156. arithmetic has practically vanished, and therefore the type CARDINAL has
  157. been eliminated. With it, the bothersome incompatibilities of operands of
  158. types CARDINAL and INTEGER have disappeared.
  159.  
  160. Pointer types are restricted to be bound to a record type or to an array
  161. type.
  162.  
  163. The notion of a definable index type of arrays has also been abandoned: All
  164. indices are by default integers. Furthermore, the lower bound is fixed to
  165. 0; array declarations specify a number of elements (length) rather than a
  166. pair of bounds. This break with a long standing tradition since Algol 60
  167. clearly demonstrates the principle of eliminating the inessential. The
  168. specification of an arbitrary lower bound hardly provides any additional
  169. expressive power. It represents a rather limited kind of mapping of indices
  170. which introduces a hidden computational effort that is incommensurate with
  171. the supposed gain in convenience. This effort is particularly heavy in
  172. connection with bound checking and with dynamic arrays.
  173.  
  174. Modules and import/export rules
  175.  
  176. Experience with Modula over the last eight years has shown that local
  177. modules were rarely used. Considering the additional complexity of the
  178. compiler required to handle them, and the additional complications in the
  179. visiblity rules of the language definition, the elimination of local
  180. modules appears justified.
  181.  
  182. The qualification of an imported object's identifier x by the exporting
  183. module's name M, viz. M.x, can be circumvented in Modula by the use of the
  184. import clause FROM M IMPORT x. This facility has also been discarded.
  185. Experience in programming systems involving many modules has taught that
  186. the explicit qualification of each occurrence of x is actually preferable.
  187. A simplification of the compiler is a welcome side-effect.
  188.  
  189. The dual role of the main module in Modula is conceptually confusing. It
  190. constitutes a module in the sense of a package of data and procedures
  191. enclosed by a scope of visibility, and at the same time it constitutes a
  192. single procedure called main program. A module is composed of two textual
  193. pieces, called the definition part and the implementation part. The former
  194. is missing in the case of a main program module.
  195.  
  196. By contrast, a module in Oberon is in itself complete and constitutes a
  197. unit of compilation. Definition and implementation parts are merged; names
  198. to be visible in client modules, i.e. exported identifiers, are marked, and
  199. they typically precede the declarations of objects not exported. A
  200. compilation generates in general a changed object file and a new symbol
  201. file. The latter contains information about exported objects for use in the
  202. compilation of client modules. The generation of a new symbol file must,
  203. however, be specifically enabled by a compiler option, because it will
  204. invalidate previous compilations of clients.
  205.  
  206. The notion of a main program has been abandoned. Instead, the set of
  207. modules linked through imports typically contains (parameterless)
  208. procedures. They are to be considered as individually activatable, and they
  209. are called commands. Such an activation has the form M.P, where P denotes
  210. the command and M the module containing it. The effect of a command is
  211. considered - not like that of a main program as accepting input and
  212. transforming it to output - as a change of state represented by global
  213. data.
  214.  
  215. Statements
  216.  
  217. The with statement of Modula has been discarded. Like in the case of
  218. imported identifiers, the explicit qualification of field identifiers is to
  219. be preferred. Another form of with statement is introduced; it has a
  220. different function and is called a regional guard (see below).
  221.  
  222. The elimination of the for statement constitutes a break with another long
  223. standing tradition. The baroque mechanism of Algol 60's for statement had
  224. been trimmed significantly in Pascal (and Modula). Its marginal value in
  225. practice has led to its absence from Oberon.
  226.  
  227. Low-level facilities
  228.  
  229. Modula makes access to machine-specific facilities possible through
  230. low-level constructs, such as the data types ADDRESS and WORD, absolute
  231. addressing of variables, and type casting functions. Most of them are
  232. packaged in a module called SYSTEM. These features were supposed to be
  233. rarely used and easily visible through the presence of the identifier
  234. SYSTEM in a module's import list. Experience has revealed, however, that a
  235. significant number of programmers import this module quite
  236. indiscriminately. A particularly seductive trap is the use of Modula's
  237. type transfer functions.
  238.  
  239. It appears preferable to drop the pretense of portability of programs that
  240. import a "standard", yet system-specific module. Type transfer functions
  241. denoted by type identifiers are therefore eliminated, and the module SYSTEM
  242. is restricted to providing a few machine-specific functions that typically
  243. are compiled into inline code. In particular, it does not contain any data
  244. types, such as ADDRESS and WORD. Individual implementations are free to
  245. provide appropriate versions of the module SYSTEM, but their facilities do
  246. not belong to the language definition. The use of SYSTEM declares a program
  247. to be patently implementation-specific and thereby non-portable.
  248.  
  249. Concurrency
  250.  
  251. The system Oberon does not require any language facilities for expressing
  252. concurrent processes. The pertinent rudimentary features of Modula, in
  253. particular the coroutine, were therefore not retained. This exclusion is
  254. merely a reflection of our actual needs within the concrete project, but
  255. not on the general relevance of concurrency in programming.
  256.  
  257. Features introduced in Oberon
  258.  
  259. In contrast to the number of eliminated features, there are only a few new
  260. ones. The important new concepts are type extension and type inclusion.
  261. Furthermore, open arrays may have several dimensions (indices), whereas in
  262. Modula they were confined to a single dimension.
  263.  
  264. Type extension
  265.  
  266. The most important addition is the facility of extended record types. It
  267. permits the construction of new types on the basis of existing types, and
  268. establishes a certain degree of compatibility between the new and old
  269. types. Assuming a given type
  270.  
  271. T = RECORD x, y: INTEGER END
  272.  
  273. extensions may be defined which contain certain fields in addition to the
  274. existing ones. For example
  275.  
  276. T0 = RECORD (T) z: REAL END
  277. T1 = RECORD (T) w: LONGREAL END
  278.  
  279. define types with fields x, y, z and x, y, w respectively. We define a type
  280. declared by
  281.  
  282. T' = RECORD (T) <field definitions> END
  283.  
  284. to be a (direct) extension of T, and conversely T to be the (direct) base
  285. type of T'. Extended types may be extended again, giving rise to the
  286. following definitions:
  287.  
  288. A type T' is an extension of T, if T' = T or T' is a direct extension of an
  289. extension of T. Conversely, T is a base type of T', if T = T' or T is the
  290. direct base type of a base type of T'. We denote this relationship by T' .
  291. T.
  292.  
  293. The rule of assignment compatibility states that values of an extended type
  294. are assignable to variables of their base types. For example, a record of
  295. type T0 can be assigned to a variable of the base type T. This assignment
  296. involves the fields x and y only, and in fact constitutes a projection of
  297. the value onto the space spanned by the base type.
  298.  
  299. It is important to allow modules which import a base type to be able to
  300. declare extended types. In fact, this is probably the normal usage.
  301.  
  302. This concept of extensible data type gains importance when extended to
  303. pointers. It is appropriate to say that a pointer type P' bound to T'
  304. extends a pointer type P, if P is bound to a base type T of T', and to
  305. extend the assignment rule to cover this case. It is now possible to form
  306. data structures whose nodes are of different types, i.e. inhomogeneous data
  307. structures. The inhomogeneity is automatically (and most sensibly) bounded
  308. by the fact that the nodes are linked by pointers of a common base type.
  309.  
  310. Typically, the pointer fields establishing the structure are contained in
  311. the base type T, and the procedures manipulating the structure are defined
  312. in the same (base) module as T. Individual extensions (variants) are
  313. defined in client modules together with procedures operating on nodes of
  314. the extended type. This scheme is in full accordance with the notion of
  315. system extensibility: new modules defining new extensions may be added to a
  316. system without requiring a change of the base modules, not even their
  317. recompilation.
  318.  
  319. As access to an individual node via a pointer bound to a base type provides
  320. a projected view of the node data only, a facility to widen the view is
  321. necessary. It depends on the ability to determine the actual type of the
  322. referenced node. This is achieved by a type test, a Boolean expression of
  323. the form
  324.  
  325. t IS T' (or p IS P')
  326.  
  327. If the test is affirmative, an assignment t' := t (t' of type T') or p' :=
  328. p (p' of type P') should be possible. The static view of types, however,
  329. prohibits this. Note that both assignments violate the rule of assignment
  330. compatibility. The desired assignment is made possible by providing a type
  331. guard of the form
  332.  
  333. t' := t(T') (p' := p(P'))
  334.  
  335. and by the same token access to the field z of a T0 (see previous examples)
  336. is made possible by a type guard in the designator t(T0).z. Here the guard
  337. asserts that t is (currently) of type T0. In analogy to array bound checks
  338. and case selectors, a failing guard leads to program abortion.
  339.  
  340. Whereas a guard of the form t(T) asserts that t is of type T for the
  341. designator (starting with) t only, a regional type guard maintains the
  342. assertion over an entire sequence of statements. It has the form
  343.  
  344. WITH t: T DO StatementSequence END
  345.  
  346. and specifies that t is to be regarded as of type T within the entire
  347. statement sequence. Typically, T is an extension of the declared type of t.
  348. Note that assignments to t within the region therefore require the assigned
  349. value to be (an extension) of type T. The regional guard serves to reduce
  350. the number of guard evaluations.
  351.  
  352. As an example of the use of type tests and guards, consider the following
  353. types Node and Object defined in a module M:
  354.  
  355. TYPE Node = POINTER TO Object;
  356. Object = RECORD key, x, y: INTEGER;
  357. left, right: Node
  358. END
  359.  
  360. Elements in a tree structure anchored in a variable called root (of type
  361. Node) are searched by the procedure element defined in M.
  362.  
  363. PROCEDURE element(k: INTEGER): Node;
  364. VAR p: Node;
  365. BEGIN p := root;
  366. WHILE (p # NIL) & (p.key # k) DO
  367. IF p.key < k THEN p := p.left ELSE p := p.right END
  368. END ;
  369. RETURN p
  370. END element
  371.  
  372. Let extensions of the type Object be defined (together with their pointer
  373. types) in a module M1 which is a client of M:
  374.  
  375. TYPE Rectangle = POINTER TO RectObject;
  376. RectObject = RECORD (Object) w, h: REAL END ;
  377. Circle = POINTER TO CircleObject;
  378. CircleObject = RECORD (Object) rad: REAL; shaded: BOOLEAN END
  379.  
  380. After the search of an element, the type test is used to discriminate
  381. between the different extensions, and the type guard to access extension
  382. fields. For example:
  383.  
  384. p := M.element(K);
  385. IF p # NIL THEN
  386. IF p IS Rectangle THEN ... p(Rectangle).w ...
  387. ELSIF (p IS Circle) & ~p(Circle).shaded THEN ... p(Circle).rad ...
  388. ELSIF ...
  389.  
  390. The extensibility of a system rests upon the premise that new modules
  391. defining new extensions may be added without requiring adaptations nor even
  392. recompilation of the existing parts, although components of the new types
  393. are included in already existing data structures.
  394.  
  395. The type extension facility not only replaces Modula's variant records, but
  396. represents a type-safe alternative. Equally important is its effect of
  397. relating types in a type hierarchy. We compare, for example, the Modula
  398. types
  399.  
  400. T0' = RECORD t: T; z: REAL END ;
  401. T1' = RECORD t: T; w: LONGREAL END
  402.  
  403. which refer to the definition of T given above, with the extended Oberon
  404. types T0 and T1 defined above. First, the Oberon types refrain from
  405. introducing a new naming scope. Given a variable r0 of type T0, we write
  406. r0.x instead of r0.t.x as in Modula. Second, the types T, T0', and T1' are
  407. distinct and unrelated. In contrast, T0 and T1 are related to T as
  408. extensions. This becomes manifest through the type test, which asserts that
  409. variable r0 is not only of type T0, but also of base type T.
  410.  
  411. The declaration of extended record types, the type test, and the type guard
  412. are the only additional features introduced in this context. A more
  413. extensive discussion is provided in [2]. The concept is very similar to the
  414. class notion of Simula 67 [3], Smalltalk [4], Object Pascal [5], C++ [6],
  415. and others, where the properties of the base class are said to be inherited
  416. by the derived classes. The class facility stipulates that all procedures
  417. applicable to objects of the class be defined together with the data
  418. definition. This dogma stems from the notion of abstract data type, but it
  419. is a serious obstacle in the development of large systems, where the
  420. possibility to add further procedures defined in additional modules is
  421. highly desirable. It is awkward to be obliged to redefine a class solely
  422. because a method (procedure) has been added or changed, particularly when
  423. this change requires a recompilation of the class definition and of all its
  424. client modules.
  425.  
  426. We emphasise that the type extension facility - although gaining its major
  427. role in connection with pointers to build heterogeneous, dynamic data
  428. structures as shown in the example above - also applies to statically
  429. declared objects used as variable parameters. Such objects are allocated in
  430. a workspace organized as a stack of procedure activation records, and
  431. therefore take advantage of an extremely efficient allocation and
  432. deallocation scheme.
  433.  
  434. In Oberon, procedure types rather than procedures (methods) are connected
  435. with objects in the program text. The binding of actual methods (specific
  436. procedures) to objects (instances) is delayed until the program is
  437. executed. The association of a procedure type with a data type occurs
  438. through the declaration of a record field. This field is given a procedure
  439. type. The association of a method - to use Smalltalk terminology - with an
  440. object occurs through the assignment of a specific procedure as value to
  441. the field, and not through a static declaration in the extended type's
  442. definition which then "overrides" the declaration given in the base type.
  443. Such a procedure is called a handler. Using type tests, the handler is
  444. capable of discriminating among different extensions of the record's
  445. (object's) base type. In Smalltalk, the compatibility rules between a class
  446. and its subclasses are confined to pointers, thereby intertwining the
  447. concepts of access method and data type in an undesirable way. In Oberon,
  448. the relationship between a type and its extensions is based on the
  449. established mathematical concept of projection.
  450.  
  451. In Modula, it is possible to declare a pointer type within an
  452. implementation module, and to export it as an opaque type by listing the
  453. same identifier in the corresponding definition module. The net effect is
  454. that the type is exported while all its properties remain hidden (invisible
  455. to clients). In Oberon, this facility is generalized in the sense that the
  456. selection of the record fields to be exported is arbitrary and includes the
  457. cases all and none. The collection of exported fields defines a partial
  458. view - a public projection - to clients.
  459.  
  460. In client modules as well as in the module itself, it is possible to define
  461. extensions of the base type (e.g. TextViewers or GraphViewers). Of
  462. importance is also the fact that non-exported components (fields) may have
  463. types that are not exported either. Hence, it is possible to hide certain
  464. data types effectively, although components of (opaquely) exported types
  465. refer to them.
  466.  
  467. Type inclusion
  468.  
  469. Modern processors feature arithmetic operations on several number formats.
  470. It is desirable to have all these formats reflected in the language as
  471. basic types. Oberon features five of them:
  472.  
  473. LONGINT, INTEGER, SHORTINT (integer types)
  474. LONGREAL, REAL (real types)
  475.  
  476. With the proliferation of basic types, a relaxation of compatibility rules
  477. among them becomes almost mandatory. (Note that in Modula the numeric types
  478. INTEGER, CARDINAL, and REAL are incompatible). To this end, the notion of
  479. type inclusion is introduced: a type T includes a type T', if the values of
  480. type T' are also values of type T. Oberon postulates the following
  481. hierarchy:
  482.  
  483. LONGREAL J REAL J LONGINT J INTEGER J SHORTINT
  484.  
  485. The assignment rule is relaxed accordingly: A value of type T' can be
  486. assigned to a variable of type T, if T' is included in T (or if T' extends
  487. T), i.e. if T J T' or T' . T. In this respect, we return to (and extend)
  488. the flexibility of Algol 60. For example, given variables
  489.  
  490. i: INTEGER; k: LONGINT; x: REAL
  491.  
  492. the assignments
  493.  
  494. k := i; x := k; x := 1; k := k+i; x := x*10 + i
  495.  
  496. conform to the rules, whereas the statements i := k; k := x are not
  497. acceptable. x := k may involve truncation.
  498.  
  499. The presence of several numeric types is evidently a concession to
  500. implementations which can allocate different amounts of storage to
  501. variables of the different types, and which thereby offer an opportunity
  502. for storage economization. This practical aspect should - with due respect
  503. for mathematical abstraction - not be ignored. The notion of type inclusion
  504. minimises the consequences for the programmer and requires only few
  505. implicit instructions for changing the data representation, such as sign
  506. extensions and integer to floating-point conversions.
  507.  
  508. .
  509.  
  510. Differences between Oberon and Revised Oberon
  511.  
  512. A revision of Oberon was defined after extensive experience in the use and
  513. implementation of the language. Again, it is characterized by the desire to
  514. simplify and integrate. The differences between the original version [7]
  515. and the revised version [9] are the following:
  516.  
  517. 1. Definition and implementation parts of a module are merged. It appeared
  518. as desirable to have a module's specification contained in a single
  519. document, both from the view of the programmer and the compiler. A
  520. specification of its interface to clients (the definition part) can be
  521. derived automatically. Objects previously declared in the definition part
  522. (and repeated in the implementation part), are specially marked for export.
  523. The need for a structural comparison of two texts by the compiler thereby
  524. vanishes.
  525.  
  526. 2. The syntax of lists of parameter types in the declaration of a
  527. procedure type is the same as that for regular procedure headings. This
  528. implies that dummy identifiers are introduced; they may be useful as
  529. comments.
  530.  
  531. 3. The rule that type declarations must follow constant declarations, and
  532. that variable declarations must follow type declarations is relaxed.
  533.  
  534. 4. The apostrophe is eliminated as a string delimiter.
  535.  
  536. 5. The relaxed parameter compatibility rule for the formal type ARRAY OF
  537. BYTE is applicable for variable parameters only.
  538.  
  539. Summary
  540.  
  541. The language Oberon has evolved from Modula-2 and incorporates the
  542. experiences of many years of programming in Modula. A significant number of
  543. features have been eliminated. They appear to have contributed more to
  544. language and compiler complexity than to genuine power and flexibility of
  545. expression. A small number of features have been added, the most
  546. significant one being the concept of type extension.
  547.  
  548. The evolution of a new language that is smaller, yet more powerful than its
  549. ancestor is contrary to common practices and trends, but has inestimable
  550. advantages. Apart from simpler compilers, it results in a concise defining
  551. document [9], an indispensible prerequisite for any tool that must serve in
  552. the construction of sophisticated and reliable systems.
  553.  
  554. Acknowlegement
  555.  
  556. It is impossible to explicitly acknowledge all contributions of ideas that
  557. ultimately simmered down to what is now Oberon. Most came from the use or
  558. study of existing languages, such as Modula-2, Ada, Smalltalk, and Cedar,
  559. which often taught us how not to do it. Of particular value was the
  560. contribution of Oberon's first user, J. Gutknecht. The author is grateful
  561. for his insistence on the elimination of dead wood and on basing the
  562. remaining features on a sound mathematical foundation. And last, thanks go
  563. to the anonymous referee who very carefully read the manuscript and
  564. contributed many valuable suggestions for improvement.
  565.  
  566. References
  567.  
  568. 1. N. Wirth. Programming in Modula-2. Springer-Verlag, 1982.
  569.  
  570. 2. N. Wirth. Type Extensions. ACM Trans. on Prog. Languages and Systems,
  571. 10, 2 (April 1988) 204-214.
  572.  
  573. 3. G. Birtwistle, et al. Simula Begin. Auerbach, 1973.
  574.  
  575. 4. A. Goldberg, D. Robson. Smalltalk-80: The Language and its
  576. Implementation. Addison-Wesley, 1983.
  577.  
  578. 5. L. Tesler. Object Pascal Report. Structured Language World, 9, 3
  579. (1985), 10-14.
  580.  
  581. 6. B. Stroustrup. The Programming Language C++. Addison-Wesley, 1986.
  582.  
  583. 7. N. Wirth. The programming language Oberon. Software - Practice and
  584. Experience, 18, 7 (July 1988), 671-690.
  585.  
  586. 8. J. Gutknecht and N. Wirth. The Oberon System. Software - Practice and
  587. Experience, 19, (1989)
  588.  
  589. 9. N. Wirth. The programming language Oberon (Revised Report). (companion
  590. paper)
  591.  
  592. File: ModToOberon2.Doc / NW 25.8.89
  593.  
  594. From Modula to Oberon
  595.  
  596. N. Wirth
  597.  
  598. Abstract
  599.  
  600. The programming language Oberon is the result of a concentrated effort to
  601. increase the power of Modula-2 and simultaneously to reduce its complexity.
  602. Several features were eliminated, and a few were added in order to increase
  603. the expressive power and flexibility of the language. This paper describes
  604. and motivates the changes. The language is defined in a concise report.
  605.  
  606. Introduction
  607.  
  608. The programming language Oberon evolved from a project whose goal was the
  609. design of a modern, flexible, and efficient operating system for a
  610. single-user workstation. A principal guideline was to concentrate on
  611. properties that are genuinely essential and - as a consequence - to omit
  612. ephemeral issues. It is the best way to keep a system in hand, to make it
  613. understandable, explicable, reliable, and efficiently implementable.
  614.  
  615. Initially, it was planned to express the system in Modula-2 [1]
  616. (subsequently called Modula), as that language supports the notion of
  617. modular design quite effectively, and because an operating system has to be
  618. designed in terms of separately compilable parts with conscientiously
  619. chosen interfaces. In fact, an operating system should be no more than a
  620. set of basic modules, and the design of an application must be considered
  621. as a goal-oriented extension of that basic set: Programming is always
  622. extending a given system.
  623.  
  624. Whereas modern languages, such as Modula, support the notion of
  625. extensibility in the procedural realm, the notion is less well established
  626. in the domain of data types. In particular, Modula does not allow the
  627. definition of new data types as extensions of other, programmer-defined
  628. types in an adequate manner. An additional feature was called for, thereby
  629. giving rise to an extension of Modula.
  630.  
  631. The concept of the planned operating system also called for a highly
  632. dynamic, centralized storage management relying on the technique of garbage
  633. collection. Although Modula does not prevent the incorporation of a garbage
  634. collector in principle, its variant record feature constitutes a genuine
  635. obstacle. As the new facility for extending types would make the variant
  636. record feature superfluous, the removal of this stumbling block was a
  637. logical decision. This step, however, gave rise to a restriction (subset)
  638. of Modula.
  639.  
  640. It soon became clear that the rule to concentrate on the essential and to
  641. eliminate the inessential should not only be applied to the design of the
  642. new system, but equally stringently to the language in which the system is
  643. formulated. The application of the principle thus led from Modula to a new
  644. language. However, the adjective "new" has to be understood in proper
  645. context: Oberon evolved from Modula by very few additions and several
  646. subtractions. In relying on evolution rather than revolution we remain in
  647. the tradition of a long development that led from Algol to Pascal, then to
  648. Modula-2, and eventually to Oberon. The common traits of these languages
  649. are their procedural rather than functional model and the strict typing of
  650. data. Even more fundamental, perhaps, is the idea of abstraction: the
  651. language must be defined in terms of mathematical, abstract concepts
  652. without reference to any computing mechanism. Only if a language satisfies
  653. this criterion, can it be called "higher-level". No syntactic coating
  654. whatsoever can earn a language this attribute alone.
  655.  
  656. The definition of a language must be coherent and concise. This can only be
  657. achieved by a careful choice of the underlying abstractions and an
  658. appropriate structure combining them. The language manual must be
  659. reasonably short, avoiding the explanation of individual cases derivable
  660. from the general rules. The power of a formalism must not be measured by
  661. the length of its description. To the contrary, an overly lengthy
  662. definition is a sure symptom of inadequacy. In this respect, not complexity
  663. but simplicity must be the goal.
  664.  
  665. In spite of its brevity, a description must be complete. Completeness is to
  666. be achieved within the framework of the chosen abstractions. Limitations
  667. imposed by particular implementations do not belong to a language
  668. definition proper. Examples of such restrictions are the maximum values of
  669. numbers, rounding and truncation errors in arithmetic, and actions taken
  670. when a program violates the stated rules. It should not be necessary to
  671. supplement a language definition with a voluminous standards document to
  672. cover "unforeseen" cases.
  673.  
  674. But neither should a programming language be a mathematical theory only. It
  675. must be a practical tool. This imposes certain limits on the terseness of
  676. the formalism. Several features of Oberon are superfluous from a purely
  677. theoretical point of view. They are nevertheless retained for practical
  678. reasons, either for programmers' convenience or to allow for efficient code
  679. generation without the necessity of complex, "optimizing" pattern matching
  680. algorithms in compilers. Examples of such features are the presence of
  681. several forms of repetitive statements, and of standard procedures such as
  682. INC, DEC, and ODD. They complicate neither the language conceptually nor
  683. the compiler to any significant degree.
  684.  
  685. These underlying premises must be kept in mind when comparing Oberon with
  686. other languages. Neither the language nor its defining document reach the
  687. ideal; but Oberon approximates these goals much better than its
  688. predecessors.
  689.  
  690. A compiler for Oberon has been implemented for the NS32000 processor family
  691. and is embedded in the Oberon operating environment [8]. The compiler
  692. requires less than 50 KByte of memory, consists of 6 modules with a total
  693. of about 4000 lines of source code, and compiles itself in about 15 seconds
  694. on a workstation with a 25MHz NS32532 processor.
  695.  
  696. After extensive experience in programming with Oberon, a revision was
  697. defined and implemented. The differences between the two versions are
  698. summarised towards the end of the paper. Subsequently, we present a brief
  699. introduction to (revised) Oberon assuming familiarity with Modula (or
  700. Pascal), concentrating on the added features and listing the eliminated
  701. ones. In order to be able to start with a clean slate, the latter are taken
  702. first.
  703.  
  704. Features omitted from Modula
  705.  
  706. Data types
  707.  
  708. Variant records are eliminated, because they constitute a genuine
  709. difficulty for the implementation of a reliable storage management system
  710. based on automatic garbage collection. The functionality of variant records
  711. is preserved by the introduction of extensible data types.
  712.  
  713. Opaque types cater for the concept of abstract data type and information
  714. hiding. They are eliminated as such, because again the concept is covered
  715. by the new facility of extended record types.
  716.  
  717. Enumeration types appear to be a simple enough feature to be
  718. uncontroversial. However, they defy extensibility over module boundaries.
  719. Either a facility to extend given enumeration types has to be introduced,
  720. or they have to be dropped. A reason in favour of the latter, radical
  721. solution was the observation that in a growing number of programs the
  722. indiscriminate use of enumerations (and subranges) had led to a type
  723. explosion that contributed not to program clarity but rather to verbosity.
  724. In connection with import and export, enumerations give rise to the
  725. exceptional rule that the import of a type identifier also causes the
  726. (automatic) import of all associated constant identifiers. This exceptional
  727. rule defies conceptual simplicity and causes unpleasant problems for the
  728. implementor.
  729.  
  730. Subrange types were introduced in Pascal (and adopted in Modula) for two
  731. reasons: (1) to indicate that a variable accepts a limited range of values
  732. of the base type and to allow a compiler to generate appropriate guards for
  733. assignments, and (2) to allow a compiler to allocate the minimal storage
  734. space needed to store values of the indicated subrange. This appeared
  735. desirable in connection with packed records. Very few implementations have
  736. taken advantage of this space saving facility, because the additional
  737. compiler complexity is very considerable. Reason 1 alone, however, did not
  738. appear to provide sufficient justification to retain the subrange facility
  739. in Oberon.
  740.  
  741. With the absence of enumeration and subrange types, the general possibility
  742. of defining set types based on given element types appeared as redundant.
  743. Instead, a single, basic type SET is introduced, whose values are sets of
  744. integers from 0 to an implementation-defined maximum.
  745.  
  746. The basic type CARDINAL had been introduced in Modula in order to allow
  747. address arithmetic with values from 0 to 216 on 16-bit computers. With the
  748. prevalence of 32-bit addresses in modern processors, the need for unsigned
  749. arithmetic has practically vanished, and therefore the type CARDINAL has
  750. been eliminated. With it, the bothersome incompatibilities of operands of
  751. types CARDINAL and INTEGER have disappeared.
  752.  
  753. Pointer types are restricted to be bound to a record type or to an array
  754. type.
  755.  
  756. The notion of a definable index type of arrays has also been abandoned: All
  757. indices are by default integers. Furthermore, the lower bound is fixed to
  758. 0; array declarations specify a number of elements (length) rather than a
  759. pair of bounds. This break with a long standing tradition since Algol 60
  760. clearly demonstrates the principle of eliminating the inessential. The
  761. specification of an arbitrary lower bound hardly provides any additional
  762. expressive power. It represents a rather limited kind of mapping of indices
  763. which introduces a hidden computational effort that is incommensurate with
  764. the supposed gain in convenience. This effort is particularly heavy in
  765. connection with bound checking and with dynamic arrays.
  766.  
  767. Modules and import/export rules
  768.  
  769. Experience with Modula over the last eight years has shown that local
  770. modules were rarely used. Considering the additional complexity of the
  771. compiler required to handle them, and the additional complications in the
  772. visiblity rules of the language definition, the elimination of local
  773. modules appears justified.
  774.  
  775. The qualification of an imported object's identifier x by the exporting
  776. module's name M, viz. M.x, can be circumvented in Modula by the use of the
  777. import clause FROM M IMPORT x. This facility has also been discarded.
  778. Experience in programming systems involving many modules has taught that
  779. the explicit qualification of each occurrence of x is actually preferable.
  780. A simplification of the compiler is a welcome side-effect.
  781.  
  782. The dual role of the main module in Modula is conceptually confusing. It
  783. constitutes a module in the sense of a package of data and procedures
  784. enclosed by a scope of visibility, and at the same time it constitutes a
  785. single procedure called main program. A module is composed of two textual
  786. pieces, called the definition part and the implementation part. The former
  787. is missing in the case of a main program module.
  788.  
  789. By contrast, a module in Oberon is in itself complete and constitutes a
  790. unit of compilation. Definition and implementation parts are merged; names
  791. to be visible in client modules, i.e. exported identifiers, are marked, and
  792. they typically precede the declarations of objects not exported. A
  793. compilation generates in general a changed object file and a new symbol
  794. file. The latter contains information about exported objects for use in the
  795. compilation of client modules. The generation of a new symbol file must,
  796. however, be specifically enabled by a compiler option, because it will
  797. invalidate previous compilations of clients.
  798.  
  799. The notion of a main program has been abandoned. Instead, the set of
  800. modules linked through imports typically contains (parameterless)
  801. procedures. They are to be considered as individually activatable, and they
  802. are called commands. Such an activation has the form M.P, where P denotes
  803. the command and M the module containing it. The effect of a command is
  804. considered - not like that of a main program as accepting input and
  805. transforming it to output - as a change of state represented by global
  806. data.
  807.  
  808. Statements
  809.  
  810. The with statement of Modula has been discarded. Like in the case of
  811. imported identifiers, the explicit qualification of field identifiers is to
  812. be preferred. Another form of with statement is introduced; it has a
  813. different function and is called a regional guard (see below).
  814.  
  815. The elimination of the for statement constitutes a break with another long
  816. standing tradition. The baroque mechanism of Algol 60's for statement had
  817. been trimmed significantly in Pascal (and Modula). Its marginal value in
  818. practice has led to its absence from Oberon.
  819.  
  820. Low-level facilities
  821.  
  822. Modula makes access to machine-specific facilities possible through
  823. low-level constructs, such as the data types ADDRESS and WORD, absolute
  824. addressing of variables, and type casting functions. Most of them are
  825. packaged in a module called SYSTEM. These features were supposed to be
  826. rarely used and easily visible through the presence of the identifier
  827. SYSTEM in a module's import list. Experience has revealed, however, that a
  828. significant number of programmers import this module quite
  829. indiscriminately. A particularly seductive trap is the use of Modula's
  830. type transfer functions.
  831.  
  832. It appears preferable to drop the pretense of portability of programs that
  833. import a "standard", yet system-specific module. Type transfer functions
  834. denoted by type identifiers are therefore eliminated, and the module SYSTEM
  835. is restricted to providing a few machine-specific functions that typically
  836. are compiled into inline code. In particular, it does not contain any data
  837. types, such as ADDRESS and WORD. Individual implementations are free to
  838. provide appropriate versions of the module SYSTEM, but their facilities do
  839. not belong to the language definition. The use of SYSTEM declares a program
  840. to be patently implementation-specific and thereby non-portable.
  841.  
  842. Concurrency
  843.  
  844. The system Oberon does not require any language facilities for expressing
  845. concurrent processes. The pertinent rudimentary features of Modula, in
  846. particular the coroutine, were therefore not retained. This exclusion is
  847. merely a reflection of our actual needs within the concrete project, but
  848. not on the general relevance of concurrency in programming.
  849.  
  850. Features introduced in Oberon
  851.  
  852. In contrast to the number of eliminated features, there are only a few new
  853. ones. The important new concepts are type extension and type inclusion.
  854. Furthermore, open arrays may have several dimensions (indices), whereas in
  855. Modula they were confined to a single dimension.
  856.  
  857. Type extension
  858.  
  859. The most important addition is the facility of extended record types. It
  860. permits the construction of new types on the basis of existing types, and
  861. establishes a certain degree of compatibility between the new and old
  862. types. Assuming a given type
  863.  
  864. T = RECORD x, y: INTEGER END
  865.  
  866. extensions may be defined which contain certain fields in addition to the
  867. existing ones. For example
  868.  
  869. T0 = RECORD (T) z: REAL END
  870. T1 = RECORD (T) w: LONGREAL END
  871.  
  872. define types with fields x, y, z and x, y, w respectively. We define a type
  873. declared by
  874.  
  875. T' = RECORD (T) <field definitions> END
  876.  
  877. to be a (direct) extension of T, and conversely T to be the (direct) base
  878. type of T'. Extended types may be extended again, giving rise to the
  879. following definitions:
  880.  
  881. A type T' is an extension of T, if T' = T or T' is a direct extension of an
  882. extension of T. Conversely, T is a base type of T', if T = T' or T is the
  883. direct base type of a base type of T'. We denote this relationship by T' .
  884. T.
  885.  
  886. The rule of assignment compatibility states that values of an extended type
  887. are assignable to variables of their base types. For example, a record of
  888. type T0 can be assigned to a variable of the base type T. This assignment
  889. involves the fields x and y only, and in fact constitutes a projection of
  890. the value onto the space spanned by the base type.
  891.  
  892. It is important to allow modules which import a base type to be able to
  893. declare extended types. In fact, this is probably the normal usage.
  894.  
  895. This concept of extensible data type gains importance when extended to
  896. pointers. It is appropriate to say that a pointer type P' bound to T'
  897. extends a pointer type P, if P is bound to a base type T of T', and to
  898. extend the assignment rule to cover this case. It is now possible to form
  899. data structures whose nodes are of different types, i.e. inhomogeneous data
  900. structures. The inhomogeneity is automatically (and most sensibly) bounded
  901. by the fact that the nodes are linked by pointers of a common base type.
  902.  
  903. Typically, the pointer fields establishing the structure are contained in
  904. the base type T, and the procedures manipulating the structure are defined
  905. in the same (base) module as T. Individual extensions (variants) are
  906. defined in client modules together with procedures operating on nodes of
  907. the extended type. This scheme is in full accordance with the notion of
  908. system extensibility: new modules defining new extensions may be added to a
  909. system without requiring a change of the base modules, not even their
  910. recompilation.
  911.  
  912. As access to an individual node via a pointer bound to a base type provides
  913. a projected view of the node data only, a facility to widen the view is
  914. necessary. It depends on the ability to determine the actual type of the
  915. referenced node. This is achieved by a type test, a Boolean expression of
  916. the form
  917.  
  918. t IS T' (or p IS P')
  919.  
  920. If the test is affirmative, an assignment t' := t (t' of type T') or p' :=
  921. p (p' of type P') should be possible. The static view of types, however,
  922. prohibits this. Note that both assignments violate the rule of assignment
  923. compatibility. The desired assignment is made possible by providing a type
  924. guard of the form
  925.  
  926. t' := t(T') (p' := p(P'))
  927.  
  928. and by the same token access to the field z of a T0 (see previous examples)
  929. is made possible by a type guard in the designator t(T0).z. Here the guard
  930. asserts that t is (currently) of type T0. In analogy to array bound checks
  931. and case selectors, a failing guard leads to program abortion.
  932.  
  933. Whereas a guard of the form t(T) asserts that t is of type T for the
  934. designator (starting with) t only, a regional type guard maintains the
  935. assertion over an entire sequence of statements. It has the form
  936.  
  937. WITH t: T DO StatementSequence END
  938.  
  939. and specifies that t is to be regarded as of type T within the entire
  940. statement sequence. Typically, T is an extension of the declared type of t.
  941. Note that assignments to t within the region therefore require the assigned
  942. value to be (an extension) of type T. The regional guard serves to reduce
  943. the number of guard evaluations.
  944.  
  945. As an example of the use of type tests and guards, consider the following
  946. types Node and Object defined in a module M:
  947.  
  948. TYPE Node = POINTER TO Object;
  949. Object = RECORD key, x, y: INTEGER;
  950. left, right: Node
  951. END
  952.  
  953. Elements in a tree structure anchored in a variable called root (of type
  954. Node) are searched by the procedure element defined in M.
  955.  
  956. PROCEDURE element(k: INTEGER): Node;
  957. VAR p: Node;
  958. BEGIN p := root;
  959. WHILE (p # NIL) & (p.key # k) DO
  960. IF p.key < k THEN p := p.left ELSE p := p.right END
  961. END ;
  962. RETURN p
  963. END element
  964.  
  965. Let extensions of the type Object be defined (together with their pointer
  966. types) in a module M1 which is a client of M:
  967.  
  968. TYPE Rectangle = POINTER TO RectObject;
  969. RectObject = RECORD (Object) w, h: REAL END ;
  970. Circle = POINTER TO CircleObject;
  971. CircleObject = RECORD (Object) rad: REAL; shaded: BOOLEAN END
  972.  
  973. After the search of an element, the type test is used to discriminate
  974. between the different extensions, and the type guard to access extension
  975. fields. For example:
  976.  
  977. p := M.element(K);
  978. IF p # NIL THEN
  979. IF p IS Rectangle THEN ... p(Rectangle).w ...
  980. ELSIF (p IS Circle) & ~p(Circle).shaded THEN ... p(Circle).rad ...
  981. ELSIF ...
  982.  
  983. The extensibility of a system rests upon the premise that new modules
  984. defining new extensions may be added without requiring adaptations nor even
  985. recompilation of the existing parts, although components of the new types
  986. are included in already existing data structures.
  987.  
  988. The type extension facility not only replaces Modula's variant records, but
  989. represents a type-safe alternative. Equally important is its effect of
  990. relating types in a type hierarchy. We compare, for example, the Modula
  991. types
  992.  
  993. T0' = RECORD t: T; z: REAL END ;
  994. T1' = RECORD t: T; w: LONGREAL END
  995.  
  996. which refer to the definition of T given above, with the extended Oberon
  997. types T0 and T1 defined above. First, the Oberon types refrain from
  998. introducing a new naming scope. Given a variable r0 of type T0, we write
  999. r0.x instead of r0.t.x as in Modula. Second, the types T, T0', and T1' are
  1000. distinct and unrelated. In contrast, T0 and T1 are related to T as
  1001. extensions. This becomes manifest through the type test, which asserts that
  1002. variable r0 is not only of type T0, but also of base type T.
  1003.  
  1004. The declaration of extended record types, the type test, and the type guard
  1005. are the only additional features introduced in this context. A more
  1006. extensive discussion is provided in [2]. The concept is very similar to the
  1007. class notion of Simula 67 [3], Smalltalk [4], Object Pascal [5], C++ [6],
  1008. and others, where the properties of the base class are said to be inherited
  1009. by the derived classes. The class facility stipulates that all procedures
  1010. applicable to objects of the class be defined together with the data
  1011. definition. This dogma stems from the notion of abstract data type, but it
  1012. is a serious obstacle in the development of large systems, where the
  1013. possibility to add further procedures defined in additional modules is
  1014. highly desirable. It is awkward to be obliged to redefine a class solely
  1015. because a method (procedure) has been added or changed, particularly when
  1016. this change requires a recompilation of the class definition and of all its
  1017. client modules.
  1018.  
  1019. We emphasise that the type extension facility - although gaining its major
  1020. role in connection with pointers to build heterogeneous, dynamic data
  1021. structures as shown in the example above - also applies to statically
  1022. declared objects used as variable parameters. Such objects are allocated in
  1023. a workspace organized as a stack of procedure activation records, and
  1024. therefore take advantage of an extremely efficient allocation and
  1025. deallocation scheme.
  1026.  
  1027. In Oberon, procedure types rather than procedures (methods) are connected
  1028. with objects in the program text. The binding of actual methods (specific
  1029. procedures) to objects (instances) is delayed until the program is
  1030. executed. The association of a procedure type with a data type occurs
  1031. through the declaration of a record field. This field is given a procedure
  1032. type. The association of a method - to use Smalltalk terminology - with an
  1033. object occurs through the assignment of a specific procedure as value to
  1034. the field, and not through a static declaration in the extended type's
  1035. definition which then "overrides" the declaration given in the base type.
  1036. Such a procedure is called a handler. Using type tests, the handler is
  1037. capable of discriminating among different extensions of the record's
  1038. (object's) base type. In Smalltalk, the compatibility rules between a class
  1039. and its subclasses are confined to pointers, thereby intertwining the
  1040. concepts of access method and data type in an undesirable way. In Oberon,
  1041. the relationship between a type and its extensions is based on the
  1042. established mathematical concept of projection.
  1043.  
  1044. In Modula, it is possible to declare a pointer type within an
  1045. implementation module, and to export it as an opaque type by listing the
  1046. same identifier in the corresponding definition module. The net effect is
  1047. that the type is exported while all its properties remain hidden (invisible
  1048. to clients). In Oberon, this facility is generalized in the sense that the
  1049. selection of the record fields to be exported is arbitrary and includes the
  1050. cases all and none. The collection of exported fields defines a partial
  1051. view - a public projection - to clients.
  1052.  
  1053. In client modules as well as in the module itself, it is possible to define
  1054. extensions of the base type (e.g. TextViewers or GraphViewers). Of
  1055. importance is also the fact that non-exported components (fields) may have
  1056. types that are not exported either. Hence, it is possible to hide certain
  1057. data types effectively, although components of (opaquely) exported types
  1058. refer to them.
  1059.  
  1060. Type inclusion
  1061.  
  1062. Modern processors feature arithmetic operations on several number formats.
  1063. It is desirable to have all these formats reflected in the language as
  1064. basic types. Oberon features five of them:
  1065.  
  1066. LONGINT, INTEGER, SHORTINT (integer types)
  1067. LONGREAL, REAL (real types)
  1068.  
  1069. With the proliferation of basic types, a relaxation of compatibility rules
  1070. among them becomes almost mandatory. (Note that in Modula the numeric types
  1071. INTEGER, CARDINAL, and REAL are incompatible). To this end, the notion of
  1072. type inclusion is introduced: a type T includes a type T', if the values of
  1073. type T' are also values of type T. Oberon postulates the following
  1074. hierarchy:
  1075.  
  1076. LONGREAL J REAL J LONGINT J INTEGER J SHORTINT
  1077.  
  1078. The assignment rule is relaxed accordingly: A value of type T' can be
  1079. assigned to a variable of type T, if T' is included in T (or if T' extends
  1080. T), i.e. if T J T' or T' . T. In this respect, we return to (and extend)
  1081. the flexibility of Algol 60. For example, given variables
  1082.  
  1083. i: INTEGER; k: LONGINT; x: REAL
  1084.  
  1085. the assignments
  1086.  
  1087. k := i; x := k; x := 1; k := k+i; x := x*10 + i
  1088.  
  1089. conform to the rules, whereas the statements i := k; k := x are not
  1090. acceptable. x := k may involve truncation.
  1091.  
  1092. The presence of several numeric types is evidently a concession to
  1093. implementations which can allocate different amounts of storage to
  1094. variables of the different types, and which thereby offer an opportunity
  1095. for storage economization. This practical aspect should - with due respect
  1096. for mathematical abstraction - not be ignored. The notion of type inclusion
  1097. minimises the consequences for the programmer and requires only few
  1098. implicit instructions for changing the data representation, such as sign
  1099. extensions and integer to floating-point conversions.
  1100.  
  1101. .
  1102.  
  1103. Differences between Oberon and Revised Oberon
  1104.  
  1105. A revision of Oberon was defined after extensive experience in the use and
  1106. implementation of the language. Again, it is characterized by the desire to
  1107. simplify and integrate. The differences between the original version [7]
  1108. and the revised version [9] are the following:
  1109.  
  1110. 1. Definition and implementation parts of a module are merged. It appeared
  1111. as desirable to have a module's specification contained in a single
  1112. document, both from the view of the programmer and the compiler. A
  1113. specification of its interface to clients (the definition part) can be
  1114. derived automatically. Objects previously declared in the definition part
  1115. (and repeated in the implementation part), are specially marked for export.
  1116. The need for a structural comparison of two texts by the compiler thereby
  1117. vanishes.
  1118.  
  1119. 2. The syntax of lists of parameter types in the declaration of a
  1120. procedure type is the same as that for regular procedure headings. This
  1121. implies that dummy identifiers are introduced; they may be useful as
  1122. comments.
  1123.  
  1124. 3. The rule that type declarations must follow constant declarations, and
  1125. that variable declarations must follow type declarations is relaxed.
  1126.  
  1127. 4. The apostrophe is eliminated as a string delimiter.
  1128.  
  1129. 5. The relaxed parameter compatibility rule for the formal type ARRAY OF
  1130. BYTE is applicable for variable parameters only.
  1131.  
  1132. Summary
  1133.  
  1134. The language Oberon has evolved from Modula-2 and incorporates the
  1135. experiences of many years of programming in Modula. A significant number of
  1136. features have been eliminated. They appear to have contributed more to
  1137. language and compiler complexity than to genuine power and flexibility of
  1138. expression. A small number of features have been added, the most
  1139. significant one being the concept of type extension.
  1140.  
  1141. The evolution of a new language that is smaller, yet more powerful than its
  1142. ancestor is contrary to common practices and trends, but has inestimable
  1143. advantages. Apart from simpler compilers, it results in a concise defining
  1144. document [9], an indispensible prerequisite for any tool that must serve in
  1145. the construction of sophisticated and reliable systems.
  1146.  
  1147. Acknowlegement
  1148.  
  1149. It is impossible to explicitly acknowledge all contributions of ideas that
  1150. ultimately simmered down to what is now Oberon. Most came from the use or
  1151. study of existing languages, such as Modula-2, Ada, Smalltalk, and Cedar,
  1152. which often taught us how not to do it. Of particular value was the
  1153. contribution of Oberon's first user, J. Gutknecht. The author is grateful
  1154. for his insistence on the elimination of dead wood and on basing the
  1155. remaining features on a sound mathematical foundation. And last, thanks go
  1156. to the anonymous referee who very carefully read the manuscript and
  1157. contributed many valuable suggestions for improvement.
  1158.  
  1159. References
  1160.  
  1161. 1. N. Wirth. Programming in Modula-2. Springer-Verlag, 1982.
  1162.  
  1163. 2. N. Wirth. Type Extensions. ACM Trans. on Prog. Languages and Systems,
  1164. 10, 2 (April 1988) 204-214.
  1165.  
  1166. 3. G. Birtwistle, et al. Simula Begin. Auerbach, 1973.
  1167.  
  1168. 4. A. Goldberg, D. Robson. Smalltalk-80: The Language and its
  1169. Implementation. Addison-Wesley, 1983.
  1170.  
  1171. 5. L. Tesler. Object Pascal Report. Structured Language World, 9, 3
  1172. (1985), 10-14.
  1173.  
  1174. 6. B. Stroustrup. The Programming Language C++. Addison-Wesley, 1986.
  1175.  
  1176. 7. N. Wirth. The programming language Oberon. Software - Practice and
  1177. Experience, 18, 7 (July 1988), 671-690.
  1178.  
  1179. 8. J. Gutknecht and N. Wirth. The Oberon System. Software - Practice and
  1180. Experience, 19, (1989)
  1181.  
  1182. 9. N. Wirth. The programming language Oberon (Revised Report). (companion
  1183. paper)
  1184.  
  1185. File: ModToOberon2.Doc / NW 25.8.89
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement