The Oberon System (1992)

Dick Pountain - 14/12/92 12:37 - BYTE

THE OBERON SYSTEM

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 lefthand track is the 'user track' where

program output appears, while the narrower righthand '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 one 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].