Oberon-2


Oberon-2 is an extension of the original Oberon programming language that adds limited reflective programming and object-oriented programming facilities, open arrays as pointer base types, read-only field export, and reintroduces the FOR loop from Modula-2.
It was developed in 1991 at ETH Zurich by Niklaus Wirth and Hanspeter Mössenböck, who is now at Institut für Systemsoftware of the University of Linz, Austria. Oberon-2 is a superset of Oberon, is fully compatible with it, and was a redesign of Object Oberon.
Oberon-2 inherited limited reflection and single inheritance without the interfaces or mixins from Oberon, but added efficient virtual methods. Method calls were resolved at runtime using C++-style virtual method tables.
Compared to fully object-oriented languages like Smalltalk, in Oberon-2, basic data types and classes are not objects, many operations are not methods, there is no message passing, and polymorphism is limited to subclasses of a common class. Oberon-2 does not support encapsulation at object or class level, but modules can be used for this purpose.
Reflection in Oberon-2 does not use metaobjects, but simply reads from type descriptors compiled into the executable binaries, and exposed in the modules that define the types and/or procedures. If the format of these structures are exposed at the language level, reflection could be implemented at the library level. It could thus be implemented almost entirely at library level, without changing the language code. Indeed, ETH Oberon makes use of language-level and library-level reflection abilities extensively.
Oberon-2 provides built-in runtime support for garbage collection similar to Java and performs bounds and array index checks, etc., that eliminate the potential stack and array bounds overwriting problems and manual memory management issues inherent in C and C++. Separate compiling using symbol files and namespaces via the module architecture ensure fast rebuilds since only modules with changed interfaces need to be recompiled.
The language Component Pascal is a refinement of Oberon-2.

Example code

The following Oberon-2 code implements a simple binary tree:

MODULE Trees;
TYPE
Tree* = POINTER TO Node;
Node* = RECORD
name-: POINTER TO ARRAY OF CHAR;
left, right: Tree
END;
PROCEDURE Insert* ;
VAR p, father: Tree;
BEGIN p := t;
REPEAT father := p;
IF name = p.name^ THEN RETURN END;
IF name < p.name^ THEN p := p.left ELSE p := p.right END
UNTIL p = NIL;
NEW; p.left := NIL; p.right := NIL; NEW; COPY;
IF name < father.name^ THEN father.left := p ELSE father.right := p END
END Insert;
PROCEDURE Search* : Tree;
VAR p: Tree;
BEGIN p := t;
WHILE & DO
IF name < p.name^ THEN p := p.left ELSE p := p.right END
END;
RETURN p
END Search;
PROCEDURE NewTree* : Tree;
VAR t: Tree;
BEGIN NEW; NEW; t.name := 0X; t.left := NIL; t.right := NIL; RETURN t
END NewTree;
END Trees.

Oberon-2 extensions to Oberon

Source:

Type-bound procedures

Procedures can be bound to a record type. They are equivalent to instance methods in object-oriented terminology.

Read-only export

The use of exported variables and record fields can be restricted to read-only access. This is shown with a "-" visibility flag.

Open arrays

Open arrays which formerly could only be declared as formal parameter types may now be declared as pointer base types.

FOR statement

The FOR statement of Pascal and Modula-2 was not implemented in Oberon. It is reintroduced in Oberon-2.

Runtime type checking

Oberon-2 provides several mechanisms for checking the dynamic type of an object. For example, where a Bird object might be instantiated to either a Duck or a Cuckoo, Oberon-2 allows the programmer to respond to the actual type of the object at runtime.
The first, most conventional, approach is to rely on the type binding system. The second approach is to use the WITH statement, which allows the dynamic subtype of a variable to be checked directly. In both cases, once the subtype has been identified, the programmer can make use of any type-bound procedures or variables that are appropriate to the subtype. Examples of these approaches are shown below.
Note that the form of WITH statement used in Oberon-2 is unrelated to the Pascal and Modula-2 WITH statement. This method of abbreviating access to record fields is not implemented in Oberon or Oberon-2.

Type binding


MODULE Birds;
TYPE
Bird* = RECORD
sound* : ARRAY 10 OF CHAR;
END;
END Birds.
MODULE Ducks;
IMPORT Birds;
TYPE
Duck* = RECORD END;
PROCEDURE SetSound* ;
BEGIN
bird.sound := "Quack!"
END SetSound;
END Ducks.
MODULE Cuckoos;
IMPORT Birds;
TYPE
Cuckoo* = RECORD END;
PROCEDURE SetSound* ;
BEGIN
bird.sound := "Cuckoo!"
END SetSound;
END Cuckoos.

WITH statement


MODULE Test;
IMPORT Out, Birds, Cuckoos, Ducks;
TYPE
SomeBird* = RECORD END;
VAR
sb : SomeBird;
c : Cuckoos.Cuckoo;
d : Ducks.Duck;
PROCEDURE SetSound* ;
BEGIN
WITH bird : Cuckoos.Cuckoo DO
bird.sound := "Cuckoo!"
| bird : Ducks.Duck DO
bird.sound := "Quack!"
ELSE
bird.sound := "Tweet!"
END
END SetSound;
PROCEDURE MakeSound* ;
BEGIN
Out.Ln;
Out.String;
Out.Ln
END MakeSound;
BEGIN
SetSound;
SetSound;
SetSound;
MakeSound;
MakeSound;
MakeSound
END Test.

POINTER


MODULE PointerBirds;
IMPORT Out;
TYPE
BirdRec* = RECORD
sound* : ARRAY 10 OF CHAR;
END;
DuckRec* = RECORD END;
CuckooRec* = RECORD END;
Bird = POINTER TO BirdRec;
Cuckoo = POINTER TO CuckooRec;
Duck = POINTER TO DuckRec;
VAR
pb : Bird;
pc : Cuckoo;
pd : Duck;
PROCEDURE SetDuckSound* ;
BEGIN
bird.sound := "Quack!"
END SetDuckSound;
PROCEDURE SetCuckooSound* ;
BEGIN
bird.sound := "Cuckoo!"
END SetCuckooSound;
PROCEDURE SetSound* ;
BEGIN
WITH bird : Cuckoo DO
SetCuckooSound
| bird : Duck DO
SetDuckSound
ELSE
bird.sound := "Tweet!"
END
END SetSound;
BEGIN
NEW;
NEW;
SetCuckooSound;
SetDuckSound;
Out.Ln; Out.String; Out.Ln;
Out.Ln; Out.String; Out.Ln;
SetSound;
SetSound;
Out.Ln; Out.String; Out.Ln;
Out.Ln; Out.String; Out.Ln;


pb := pd;
SetDuckSound;
Out.Ln; Out.String; Out.Ln;
pb := pc;
SetCuckooSound;
Out.Ln; Out.String; Out.Ln;

SetSound;
Out.Ln; Out.String; Out.Ln;
pb := pd;
SetSound;
Out.Ln; Out.String; Out.Ln;

NEW;
SetSound;
Out.Ln; Out.String; Out.Ln
END PointerBirds.

IS operator

A third approach is possible using the IS operator. This is a relation operator with the same precedence as equals, greater, etc. but which tests dynamic type. Unlike the two other approaches, however, it does not allow the programmer access to the subtype that has been detected.

Syntax

The development of the ALGOLPascalModula-2 → Oberon → Component Pascal language family is marked by a reduction in the complexity of the language syntax. The entire Oberon-2 language is described using only 33 grammatical productions in the extended Backus–Naur form, as shown below.

Module = MODULE ident ";" DeclSeq END ident ".".
ImportList = IMPORT ident ";".
DeclSeq = .
ConstDecl = IdentDef "=" ConstExpr.
TypeDecl = IdentDef "=" Type.
VarDecl = IdentList ":" Type.
ProcDecl = PROCEDURE IdentDef ";" DeclSeq END ident.
ForwardDecl = PROCEDURE "^" IdentDef .
FormalPars = "" .
FPSection = ident ":" Type.
Receiver = "".
Type = Qualident
| ARRAY OF Type
| RECORD FieldList END
| POINTER TO Type
| PROCEDURE .
FieldList = .
StatementSeq = Statement.
Statement =
| IF Expr THEN StatementSeq END
| CASE Expr OF Case END
| WHILE Expr DO StatementSeq END
| REPEAT StatementSeq UNTIL Expr
| FOR ident ":=" Expr TO Expr DO StatementSeq END
| LOOP StatementSeq END
| WITH Guard DO StatementSeq END
| EXIT
| RETURN
].
Case = .
CaseLabels = ConstExpr .
Guard = Qualident ":" Qualident.
ConstExpr = Expr.
Expr = SimpleExpr .
SimpleExpr = Term.
Term = Factor.
Factor = Designator | number | character | string | NIL | Set | "" | "~" Factor.
Set = "".
Element = Expr .
Relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
AddOp = "+" | "-" | OR.
MulOp = "*" | "/" | DIV | MOD | "&".
Designator = Qualident.
ExprList = Expr.
IdentList = IdentDef.
Qualident = ident.
IdentDef = ident .

Implementations

Oberon-2 compilers maintained by ETH include versions for Windows, Linux, Solaris, macOS.
The compiles to native machine code and can use a JIT on Windows, Linux, and macOS. It is created and maintained by Mike Spivey and uses the Keiko Virtual Machine.
There is an Oberon-2 Lex scanner and Yacc parser by Stephen J. Bevan of Manchester University, UK, based on the one in the Mössenböck and Wirth reference. It is at version 1.4.
There is a release named Native Oberon which includes an operating system, and can directly boot on PC class hardware.
A .NET implementation of Oberon with the addition of some minor.NET-related extensions has been developed at ETHZ.
is a very simple integrated development environment, which is provided with editor, linker, and Oberon-2 compiler. This compiles to Windows executables. Full source code is provided; the compiler is written in Oberon-2.
The was written at the University of Vologda in Russia. It produces object code in the form of Java class files. Some JOB-specific classes are provided which are Java compatible, but which use a more Oberon-like component hierarchy.
The compiles to C, using the GNU Compiler Collection toolchain for program generation.
is a compiler that translates the full Oberon language into JavaScript. The compiler is written in JavaScript and can thus be called from Web pages to process scripts written in Oberon.
is a development system by Excelsior LLC, Novosibirsk, Russia. It contains an optimizing compiler for Intel Pentium, or "via-C" translator for cross-platform software development. Available for Windows and Linux. The compiler is written in Oberon-2 and compiles itself.
is a project to bring Oberon 2 and Component Pascal to Linux and Win32. The Linux port of BlackBox was unavailable before and it originally ran on only Microsoft Windows.
XOberon is a real-time operating system for PowerPC, written in Oberon-2.
The Portable Oberon-2 Compiler was developed to port the Oberon System onto commercially available platforms.

Keiko bytecode

Oberon-2 can target the Keiko Virtual machine.
For example, like some other language compilers,
the first compiles to an intermediate bytecode which can be interpreted with a byte-code interpreter or use just-in-time compilation.