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].