[Oberon] Potential New Approach to Implement Instance-Centered OOP in Oberon-07
Andreas Pirklbauer
andreas_pirklbauer at yahoo.com
Sat Oct 3 11:48:50 CEST 2026
The Oberon-2 programming language offers a convenient notation for object-oriented programming (OOP), namely that of type-bound procedures. It is valuable in education. However, Oberon-2 uses a class-centered view rather than an instance-centered view, meaning that Oberon-2-style type-bound procedures (methods) can essentially be viewed as constants: the same procedure is bound to all instances of a type. This reflects the reality that, in most typical applications, the same procedure (handler) is indeed bound to all instances of a class.
One advantage of this approach is that a programmer cannot accidentally forget to initialize the method bindings. A disadvantage is that the bindings are fixed at the type level. This makes a new feature necessary, namely method overriding. This in turn complicates the language and the compiler and, in fact, the conceptual model. See an earlier discussion of this topic, “Class Methods vs. Procedure Variables in Records,” on this mailing list in 2017.
The Graphics module provides an example where the alternative view, namely the instance-centered view, is implemented “manually”. This is done by declaring a method record and initializing its method fields manually in the module initialization body. This is somewhat cumbersome and requires some discipline from the programmer.
This raises the question whether one could combine the two approaches with the following new construct:
Part A: Replace ObjectDesc and MethodDesc
-------
Instead of the following declaration (see Graphics.Mod)
TYPE
ObjectDesc* = RECORD
x*, y*, w*, h*: INTEGER;
col*: BYTE;
selected*, marked*: BOOLEAN;
do*: Method; (*<---*)
next: Object
END ;
MethodDesc* = RECORD
new: Modules.Command; (*<---*)
copy: PROCEDURE (from, to: Object);
draw: PROCEDURE (obj: Object; VAR msg: Msg);
change: PROCEDURE (obj: Object; VAR msg: Msg);
selectable: PROCEDURE (obj: Object; x, y: INTEGER): BOOLEAN;
...
END ;
use:
TYPE
ObjectDesc* = RECORD (*<-- no more “do” field*)
x*, y*, w*, h*: INTEGER;
col*: BYTE;
selected*, marked*: BOOLEAN;
next: Object
BEGIN (*signatures*)
copy: PROCEDURE (from, to: Object);
draw: PROCEDURE (obj: Object; VAR msg: Msg);
change: PROCEDURE (obj: Object; VAR msg: Msg);
selectable: PROCEDURE (obj: Object; x, y: INTEGER): BOOLEAN;
...
END;
The BEGIN section declares the operations supported by the record type, including their signatures. These are not ordinary record fields; they define the dispatch interface of the type. They effectively are forward declarations (a small drawback, as the compiler now has to check the equality of the signatures)
Part B: Extend the intrinsic procedure NEW such that it essentially becomes a constructor
-------
NEW(obj,
copy, CopyLine,
draw, DrawLine,
change, ChangeLine,
selectable, LineSelectable,
…);
The compiler would require NEW to provide an implementation for every operation declared in the BEGIN section. We use the keyword BEGIN deliberately to suggest that, very much like the BEGIN section of a module, it is used to initialize the various fields of an instance. In this case, the initialization is performed by NEW, and it is enforced by the compiler.
This approach would essentially implement the same functionality as the original Graphics module—i.e. an instance-centered view—but without much of its boilerplate code and without the risk of accidentally forgetting to initialize the various method fields. Since the bindings are instance-specific, no overriding mechanism is necessary.
It seems that this could provide an elegant way of implementing OOP without introducing any new language keywords. The implementation would of course be much simpler than type-bound procedures.
Has anyone seen or done experiments in this direction?
More information about the Oberon
mailing list