The Oberon System (1992)
Dick Pountain - 14/12/92 12:37 - BYTE
Professor Niklaus Wirth is known far beyond the borders of his native
Switzerland, as the designer of the Pascal and Modula-2 languages.
Oberon, his latest language, is not yet in widespread use though there
are a number of public-domain compilers in circulation. Oberon is more
than just a language; it's one part of a research project which
comprises an engineering workstation, its operating system and the
compiler. What's more the Oberon operating system is a radically
object-oriented design that prefigures many of the features that will
be seen in our next-generation PC operating systems.
Whether it's IBM and Apple's Taligent, Microsoft's 'Cairo' version of
Windows, GO Corporation's Penpoint or Apple's Newton OS, there is sure
to be an object-oriented operating system somewhere in your future. At
the moment few computer users have much idea of what a truly
object-oriented operating system will look like, or just how much it
will alter our concepts of computer software. A recent encounter with
the Oberon system has given me a much better idea of what to expect,
and I'm impressed. Under Oberon the notion of an application program
completely disappears in favor of groups of small programs called
tools. The operating system understands fundamental data types like
structured texts and pictures, and 'applications' are just customized
viewers for these types that add new functions.
SOME BACKGROUND
Starting in 1985, Wirth and his fellow professor Jurg Gutknecht at ETH
(the Eidgenossische Technische Hochschule in Zurich) designed the
Oberon language and operating system in parallel with development of
their Ceres workstation project. Ceres and Oberon became a test-bed
for Wirth's philosophy of achieving reliability through simplicity --
he's fond of quoting Albert Einstein's famous epigram "Make it as
simple as possible but not simpler". In his book on the Oberon system
Wirth argues forcefully that modern software (both system and
application) has become grossly overweight and inefficient, and that
consequently the semiconductor industry's continual improvements in
memory size and processor speed are being squandered for minimal
performance gains. Software development lags behind hardware,
progressing by a fossil-like process of accretion in which extra
layers of code are grafted on to adapt obsolete systems. Wirth's
argument is not primarily economic, for memory and CPU power are
indeed becoming cheap commodities -- his objection to inflated size is
that it brings with it unreliability. The probability of introducing
bugs increases explosively with program size, so smaller systems are
also likely to be more reliable systems. Any unbiassed observer of
current systems (Unix, Windows, OS/2) must find it hard to disagree
with his verdict.
Wirth's prescription for fighting the flab is extensibility -- the
ability to add to a system by extending its existing capabilities,
rather than continually duplicating them. For example it's wasteful to
incorporate new text-editing code into every application, when all
could share a centrally provided basic editor and customize it for
particular purposes. To write an extensible system you need an
extensible language which allows you to add modules that reuse the
built-in data structures without forcing you to recompile the whole
operating system. The Oberon language resembles a stripped-down
Modula-2 with the added ability to extend data types, so that new data
types can inherit features from existing ones. Oberon programmers
write in object-oriented style by installing special procedures called
'handlers' that bind methods to data objects at run-time. The latest
version, Oberon-2, is fully object-oriented with explicit binding of
methods to types. [The Oberon language was more fully described in
Byte, March 1991, page 135.]
The ETH researchers started with a completely clean slate in both
hardware and software, unencumbered by any requirements for backward
compatibility, industry standards or commercial acceptability. Ceres
(now into its third generation, Ceres-3) is a single-board graphical
workstation driven by a National Semiconductor NS32GX32 CPU. It's
features include a 1024 x 800 color screen, three button mouse, 4 to 8
Mbytes of memory and a simple serial network interface based on RS485.
Over 100 Ceres are used daily by students and staff in ETH labs.
ETH now has public-domain versions of the Oberon operating system and
compiler for other platforms including IBM PC and Apple Macintosh (see
end of article). Each port took around 6 man-months, which suggests
that the philosophy is working -- the PC version occupies just 1.5
Mbytes of hard disk space including the source code.
THE OBERON USER INTERFACE
It's almost impossible to explain the Oberon system without
considering its user interface first. Oberon employs a GUI with
built-in support for fonts and bitmaps, but with tiled rather than
overlapping windows. Wirth and Gutknecht reject the overlapping
windows metaphor as too much complication for a small advantage --
though I suspect that this is an argument they have already lost to
millions of Mac and Windows users. Programmers can easily produce
overlapping windows as an extension.
The Oberon screen is split vertically into two 'tracks' each
containing several non-overlapping panes called 'viewers' stacked one
above the other. The wider left-hand track is the 'user track' where
program output appears, while the narrower right-hand 'system track' is
used for system messages and commands. You can type text into any
viewer by setting the caret cursor in it with a mouse click.
Everything in Oberon happens within viewers, so there is no main menu
bar at the top of the screen (see fig.1). Each viewer has three parts:
a main area for text and pictures; a vertical scroll bar; and a
reverse-video bar that holds the viewer's title and a list of commands
that looks like a horizontal menu. I deliberately said 'looks like'
because the Oberon system is completely modeless and so strictly
speaking has no concept of a menu -- all text that appears on an
Oberon screen is treated in exactly the same way and is always
editable. A disk directory listing, the commands in the title bar,
even system messages are all editable (and maybe executable) text.
You can execute any text string which names a valid Oberon command by
pointing and clicking the middle mouse button, no matter where it
appears on the screen. Oberon commands are always of the form
<module>.<command> (eg. Edit.Copy, Draw.Erase) and are simply the
qualified names of procedures exported from an Oberon module. When you
compile your own Oberon modules, your new procedures immediately
become available as commands.
You tend to work in Oberon by setting up small scratchpad viewers in
the system track which hold the names of all the commands you are
currently working with; these viewers are in effect user-defined menus
and you need never type any command's name more than once. You may not
need to type it at all since you can load texts called 'tools' from
disk, that list all the commands exported by a particular module. Some
of the tools provided with Oberon are System, Edit, Draw, Paint and
Write, and Compiler. The Edit tool provides just the most basic
editing functions (like the Mac or Windows Notepad editor) of cutting,
copying and pasting with the mouse, but the Write tool (an extension
of Edit) is a full document editor with fonts and formatting.
Executing any one of a tool's commands causes the operating system to
load the corresponding module if it's not already in memory; there is
no explicit program loading in Oberon.
Most Oberon commands take their operands from the screen. For example
you might select a stretch of text with the mouse and then execute the
Edit.Copy command on that selection. To make a whole viewer the input
for a command you mark it by placing the cursor in it and pressing the
mark key. You can apply any tool to any viewer, and to the output of
any previous command. For example I might list a disk directory (by
clicking System.Directory), then select a file name from the newly
opened Directory viewer and click Write.Open to edit that file in a
new Write viewer.
You can run the compiler on any viewer that contains Oberon source,
compile into memory and then run the new commands; it's very like the
Turbo Pascal environment, with compilation so fast that it feels like
an interpreter. I found the whole Oberon system very fast and
convenient once I'd mastered the initially daunting mouse button
combinations, and no, I didn't miss having to push overlapping windows
around.
THE STRUCTURE OF OBERON
The Oberon system offers a very different model of computer/user
interaction from that offered by, say, Unix, MS-DOS or Windows. For
example it has no concept of a 'program' comparable to a .EXE file.
Oberon's unit of action is a single procedure call, or command, while
the unit of compilation is a module which may export several commands.
Commands must be parameterless procedures, and they receive their
run-time arguments (such as screen selections) via a system variable
called Oberon.Par.
Commands are atomic actions which cannot be interrupted before
completion (except by the abort key). This means that Oberon commands
can't interact with the user, which is why you always specify a target
before executing the command -- there are no dialogs in Oberon, and
very few input statements. Consecutive Oberon commands normally swap
data via persistent data structures in main memory, whereas under DOS
or Unix the output from program almost always has to be written to
disk before it can be loaded into a second program.
Oberon loads modules dynamically on demand, like Windows DLLs, and
they then remain memory resident unless the user manually issues a
<module>.Free command. Machines, like the Ceres workstation, which
possess a hardware MMU (Memory Management Unit) use it to load modules
by raising page faults, and to protect modules once in memory. The
Oberon kernel contains a garbage collector which operates in the
background (ie. between procedure calls) to free up heap space that is
no longer in use, so freeing Oberon programmers from the chore of
explicit memory deallocation and all the infuriatingly obscure bugs it
can introduce.
The Oberon compiler has no separate linking phase, since all linking
takes place at module load-time (again like a DLL). This saves on
system resources in two significant ways. Firstly, the binary images
of 'programs' on disk are minimally small as they don't contain linked
copies of all the modules they import -- contrast DOS, where you might
have several applications on your hard disk that each contain a linked
copy of the same huge graphics library. Secondly less RAM is consumed
because only one copy of any module is ever loaded, no matter how many
client modules share it. As a third bonus, whenever you upgrade to a
new module version, all its clients automatically get upgraded too.
Oberon is a single process operating system, but you can run multiple
tasks through a very simple form of task switching. When you select a
new viewer as the target for future commands you are in effect
switching tasks, but only one command can be executing at any time.
Whenever it is not executing a command, Oberon runs a single central
polling loop that watches for keyboard, mouse and network events (see
fig. 2). To prevent such events being lost while the CPU is executing
a command, they are queued in buffers controlled via hardware
interrupts; these interrupts are hidden within their respective device
drivers and simply return control to the point of interruption, so
they are invisible to user programs. A programmer can insert new code
into the polling loop, but only to monitor new event sources such as a
modem port.
As long as commands are quick in execution (normally the case since
they are non-interactive) this simple scheme produces an effective
illusion of multitasking, rather like TSR programs under DOS, but of
course if you write a command that computes a billion decimal places
of pi it will tie up the machine. On the plus side, the operating
system is very robust since tasks can never interact in unexpected
ways, which eliminates huge swathes of protection code that would
otherwise be needed. The Oberon disk file system is equally simple,
and uses a B-tree directory structure for speedy access.
The most important single design feature of Oberon is the decoupling
of data from the way it is viewed. Viewers display the contents of
abstract documents such as texts, graphs and pictures. Documents are
active objects which contain commands to change their own contents,
and whenever such a change occurs, the document broadcasts a message
to all viewers so they can update their views of it. In short,
documents are responsible for their own content, while viewers know
how to format and display that content -- the generic viewer object
(called a 'frame') does not need to know the type of its contents.
This decoupling enables you to extend the Oberon system by adding new
document types and their viewers without recompiling or duplicating
ANY of the code of their parent types. It also means that adding new
commands to an existing document type cannot interfere in any way with
the operations of its viewer.
Fig. 3 shows a graph of module dependencies for the Oberon core, where
arrows signify one module importing another (where an indirect path
also exists, direct imports have been omitted for clarity). It's a
strictly hierarchical, acyclic, structure with hardware-dependency
entirely confined to the driver layer. In Wirth's description the
system 'imports hardware' at the bottom level and 'exports commands to
the user' at the top level. The whole core operating system occupies
only 131 Kbytes including the Oberon compiler, which is smaller than
most Windows utilities. There are only three assembler modules
(Kernel, Display and Reals) all the rest being written in Oberon, and
the 12,000 lines of source code for these is supplied with the system.
It's quite feasible (Wirth would probably say desirable) for a
programmer to understand the workings of the whole operating system.
TEXTS AND WRITE ELEMENTS
The abstract data type Text has a special importance in Oberon, and is
encapsulated at the heart of the operating system. An Oberon text is
defined as a sequence of attributed characters, whose attributes are
ASCII code, font, color and vertical offset (the last three are
collectively called a 'look'). Text is a far more powerful concept
than String, the building block of more conventional systems, since it
already includes the concept of appearance. Texts are divided up into
'runs', sequences of characters that all share the same look.
Texts are active objects which know how to edit themselves, through
the basic methods Delete, Insert, Append and ChangeLooks, and how to
Store and Load themselves from disk. They do not know about font
rendering or printing, which is the job of their viewer, an object of
type TextFrame. A TextFrame clips a text to fit the viewing window and
renders the characters onto the screen using Oberon's built-in font
engine. Since all interaction with the user occurs via viewers, a
TextFrame also tracks the mouse and interprets editing commands (via
its handler procedure) which are passed to the text itself for
execution. TextFrames employ a very efficient single pass font
rendering algorithm which expects a fixed line spacing throughout the
frame, so you can't mix different font sizes in the same frame, though
you can mix different styles. However frames are nestable, so Oberon
text editors employ embedded subframes to display headlines etc.
Write is one such text editor, written by Clemens A. Szyperski and now
shipped as part of the Oberon system. Write extends the concept of a
text to a sequence of attributed 'elements', where an element can be a
ordinary character or an extended active (or even interactive) object.
Write elements float in the text sequence like any other character,
but the screen display they produce may be radically different; maybe
a box containing a picture; a 'hot' graph display; or even a whole
interactive application like a CAD drawing editor. Elements are not
implemented as frames, which would violate the decoupling of data from
view, but they are free to install a subframe with a new set of
commands tailored to their own purpose. When a viewer encounters an
element it sends it the 'prepare' message, and the element replies to
tell the viewer how much screen space it will require. Write elements
allow you to edit any kind of data object in situ, using its own
appropriate editor, merely by clicking the mouse within its frame; the
same effect as Microsoft's OLE achieved elegantly and implicitly
rather than as a bolted-on afterthought.
From a portability viewpoint Write elements possess one very
attractive feature -- you can still process a document containing
elements even if their required code module is not available. Such
elements just appear as character-sized empty boxes embedded in the
text. As soon as you acquire the necessary module, the elements 'come
to life' again.
Write formats documents by embedding markers in the text which affect
all text up to the next marker. These markers are called 'parcs',
short for PARagraph Control elements. Parcs normally appear as white
space but the Write.Parcs command makes them visible as
Macintosh-style ruler lines, and you can apply various mouse click
combinations to a visible parc to alter the layout and look of the
following paragraph interactively.
ETH students have written dozens of special Write element types. For
example ErrorElems are placed by the Oberon compiler next to errors in
your program text; they display an error message when you click on
them and disappear upon re-compilation. Adaptive LineElems draw
horizontal rules that automatically adjust to the margin width.
TableElems display structured tables, and clicking on them displays
the declarative description of the table format for editing.
StyleElems are named parcs that define global styles. CalcElems are
spreadsheet cells. FoldElems collapse a text like an outliner.
PopupElems produce a pop-up menu, allowing you create new user
interfaces. Other elements let you embed buttons, icons and hypertext
links. Any programmer can write new element types to turn Write into a
customized editor.
I first used the Oberon system on a very special custom workstation
called Chameleon, developed by Cuno Pfister and Beat Heeb at ETH. This
remarkable machine contains a fast MIPS3000 RISC processor, seven
Algotronix CAL1024 field programmable gate-array chips and very little
else apart from memory and a color palette. One of the CAL chips is
programmed at boot-time to implement the workstation's I/O and display
logic, and the remaining six are free for the engineer-user to develop
custom circuits. The whole Chameleon machine is specified in a
hardware design language called Debora which strongly resembles
Oberon, and was completed in three months from scratch! Pfister and
Heeb have extended Write with interactive custom elements to create a
visual CAL layout editor, a circuit simulator called DebSim, and a
graphical CAL debugger that displays the state of CAL elements in
real-time. The documentation contains active illustrations which are
not just pictures but spring to life when you click them.
A CLEAN START
When I first wrote about the Oberon language two years ago I
restrained myself from describing the operating system because it
seemed too remote from mainstream commercial computing. How quickly
things change. Now both the IBM/Apple/Taligent consortium and
Microsoft boast of their adoption of 'microkernels' for future
versions of their operating systems, as well as extensibility through
deep object-orientation. Everyone has finally realized that you can't
plaster new layers over already bloated systems for ever, that a
return to clean roots is necessary. The big OS vendors won't go so far
down the road of minimalism as Wirth and Gutknecht have, because
they've spent years convincing users that they need preemptive
multitasking and overlapping windows. Nevertheless the Oberon system
is a beautiful example of how to do more with less, which you can
sample for free as a peek into an alternative future.
INFORMATION PANEL
Oberon implementations for Apple Macintosh II, Digital Equipment
DECstation, IBM PC (MS-DOS), IBM R/S6000 and Sun SPARCstation are
available without fee (there may be a shipping charge) from :-
The Secretary,
Institut fur Computersysteme,
ETH,
8092 Zurich,
Switzerland.
Tel: (+41-1)-254-7311
Fax: (+41-1)-261-5389
The Oberon System is described in full in :-
Project Oberon -- Niklaus Wirth and Jurg Gutknecht
ISBN 0-201-54428-8
The Oberon System User Guide and Programmer's Manual -- Martin Reiser
ISBN 0-201-54422-9
Programming in Oberon -- Martin Reiser and Niklaus Wirth
ISBN 0-201-56543-9
All published by Addison-Wesley
[Mike -- Fig.1 will be a screen-shot of an Oberon display which I'll
send on later when my PC version arrives].