Oberon/F (1994)

Dick Pountain - 10/10/94 11:06 - Oberon/F


Oberon/F is the latest recruit to that important new 

software category, the object-oriented component 

framework. XVT and NextStep's Interface Builder are 

probably the most famous current exemplars, but Taligent's 

TalAE will soon be contesting that title. Oberon/F 

provides a thin object-services layer which runs on top of 

the host operating system and enables you to write 

cross-platform portable and extensible applications as if 

the host OS supported full object-orientation. Currently 

Oberon/F runs on Win32s for Windows 3.1, NT and 95 and on 

Macintosh System 7, but versions are planned for OS/2 and 

Unix/Motif. 

Why component frameworks? Mostly because the class library 

based approach to OOP which promised to deliver software 

reuse has in practice have often disappointed (see 

"Componentware", May 1994 Byte). Component frameworks aim 

both to reduce the huge learning-curve of class libraries 

and to enable software reuse by supplying big, 

already-useful chunks. If using a class library is like 

buying a load of bricks, then using a framework is like 

erecting a pre-fabricated house, with the walls already 

assembled.

Oberon/F is wholly document-centric framework in which 

everything is a document that you can edit within the 

development system, which also serves as the runtime 

system. Every Oberon/F document contains one or more 

'views', software components that enable viewing and 

editing of a particular data type eg. a text, a picture or 

a spreadsheet. Each view is implemented by a separate 

module, which gets dynamically linked and loaded on demand 

like a DLL, but unlike Windows DLLs (or VBXs) you can 

extend Oberon modules. If the appropriate module is 

present, any Oberon/F document editor can edit any type of 

view, so the concept of applications owning files has 

completely dissolved. 

Oberon/F incorporates a highly-efficient but proprietory 

compound document model that allows you to embed views 

into one each other in arbitrarily complex ways. In future 

releases this system will be progressively integrated with 

the COM and DSOM models used in OLE 2 and OpenDoc. 


THE DEVELOPMENT ENVIRONMENT

Where NextStep and Taligent are based on Objective-C and 

C++ respectively, Oberon/F is based on the Oberon 2 

language, Niklaus Wirth's successor to Pascal and Modula 

2, and includes a compiler and debugger for the language. 

(The Oberon/F system is being developed by Oberon 

Microsystems inc. of Zurich, Switzerland, a commercial 

firm founded by ETH alumni with Wirth as a director.) 

Oberon is a strongly-typed, compiled language which 

supports both modular and object-oriented programming, and 

also Eiffel-like precondition and postcondition testing 

using ASSERT statements. Unusually for a compiled language 

it features an automatic garbage collector to preserve 

memory integrity. (Taligent too has recognized that 

extensible programming and 'malloc' don't mix, and is 

adding garbage collection to its C++ compiler.) The 

driving force throughout the Oberon project has been the 

pursuit of simplicity, well illustrated by the fact that 

my beta-0.9 Oberon/F system arrived on a single 1.4 Mbyte 

floppy disk and occupies barely 4 Mbytes of hard disk 

space.

The programming, editing and debugging environment is 

completely integrated, giving it the same sort of feel as 

interactive interpreted systems like Smalltalk or Lisp - 

this is an illusion as Oberon compiles straight to 32-bit 

native 486 or 680x0 code. However the compiler is so fast 

at 15,000 odd lines per minute and the modules you write 

are typically so small that compilation time is seldom 

noticeable. 

The compiler, debugger and other software tools are all 

based on Oberon/F compound documents; they are active, 

editable texts containing hypertext-style embedded 

objects. For example in a Show Loaded Modules window you 

can highlight any module name in the list and immediately 

decompile its interface definition; in a debug window 

clicking on diamond-shaped markers lets you follow 

pointers and traverse lists; in the editor errors are 

flagged by markers embedded in the text which expand into 

error messages when clicked.


TEXTS

The first release of Oberon/F provides - in addition to 

the Development subsystem - just two component subsystems 

called Texts and Forms. An ODBC database subsystem is 

planned for the second release. In-place editing of 

industry-standard graphics and spreadsheet formats will 

not become available until a later release supports OLE 2. 

The Text subsystem is a wordprocessor with features 

roughly equivalent to Windows Write (eg. it supports 

fonts, paragraph attributes and object embedding), but 

unlike Write you can extend this editor in any way you 

like. As a test example I decided to add the ability to 

change a selected passage of text into upper-case (see the 

code in Listing 1). A rather minor achievement you might 

think, but consider these points:


1) This is not just a macro (as is, say, WordBasic) but a 

native 486 code extension to the system.

2) This new ability is available within ANY piece of text 

whatsoever in Oberon/F, and will be too in any future 

programs that I add.

3) I didn't need to recompile the text editor and indeed 

have never even seen its source code, only the published 

programming interface.

4) This same code works identically on a Windows PC or a 

Macintosh and automatically displays the proper 

'look-and-feel' of either platform.


In Oberon/F exported parameterless procedures are called 

commands and are executable from anywhere in the system. 

The procedure UpCase* (the asterisk indicates it's to be 

exported by the module DickText) is a command which 

performs its action on the selection of the window which 

currently has the focus. You can execute commands by 

selecting any instance of their name on the screen and 

using the debugger's Execute command, by building 

interactive 'tools' containing clickable embedded 

'commander' buttons, or more conventionally by installing 

them into the regular Windows or Mac menu bar. The menu 

system is defined in an Oberon/F document that you can 

edit like any other, and you can even install the new 

menus on-the-fly without restarting the system.

You can program Oberon/F at three levels of complexity, 

and my little example illustrates the simplest, command 

programming, which adds new functions to an existing view. 

The next higher level is the writing of new views, ie. 

visual representations for data types. The third, and 

hardest level is the writing of 'container' views which 

can contain other embedded views; Oberon/F editors are 

normally container views.


FORMS

The Forms component is a simple visual design tool for 

data entry forms and dialogs. First you write a code 

module that defines a record data type with various 

fields, and then you design the corresponding form by 

visually dragging control objects around on it as in 

Visual Basic. Thereafter the Oberon/F runtime system 

creates and maintains the connections between the screen 

fields and the underlying data structure without you 

having to write any further code, automatically updating 

the field variables whenever the user enters data into the 

form. The reverse process is not automatic, so when your 

program updates a record field it must broadcast an update 

message telling all screen views that they need to change 

too.

Oberon/F forms are stored as documents like any other and 

you can modify their visual appearance without forcing a 

recompilation of the application code, a great advantage 

compared to conventional code generators. You can embed 

forms in texts and vice-versa, recursively to any depth, 

to construct a wide variety of user-interface styles. The 

beta-release I tested supported the standard Windows and 

Mac control types (text fields, captions, scroll bars, 

push buttons, radio buttons, and check boxes) but Oberon 

Microsystems are working to support OLE 2's .OCX format so 

that future Visual Basic custom controls will be usable 

from within Oberon/F. 


MODELS, VIEWS AND CONTROLLERS

Oberon/F is designed around a heirarchy of abstractions 

that isolate modules from the physical hardware (for 

cross-platform portability) and from one another (for 

extensibility). The physical display, printing and file 

systems are hidden in abstract object classes and are 

accessed by creating reader and writer objects for them. 

The most fundamental data type is a Store which represents 

a body of persistent data that knows how to save and 

retrieve itself from a non-volatile medium like a hard 

disk. The module 'Stores' supplies readers and writers 

that can map Oberon data types like characters, integers, 

sets and other stores into binary data; stores can contain 

other embedded stores and hence can represent compound 

documents. Store is an abstract type that is never 

instantiated directly; instead Oberon/F supplies three 

extensions of Store called Models, Views and Controllers. 

This MVC (Model-View-Controller) paradigm was originally 

devised by the Smalltalk team at Xerox PARC; it divorces 

the presentation of data from its storage and abstracts 

from the OS-specific details of windows. 

Crudely put, the model is the data itself while a view is 

a particular presentation of the data transformed into a 

rectangular display area. There may be many views onto the 

same model, and if the model is changed this fact must be 

broadcast to all views by sending messages. A view might 

directly handle interaction with the user's mouse and 

keyboard, but in complex applications this task is usually 

delegated to a Controller object. Models, Views and 

Controllers are themselves extensible, and in Listing 1 

you'll see the use of a TextController object 'c' to 

measure the current text selection, while the actual 

processing takes place directly on a TextModel called 

'buf'.  


SAFETY FIRST  

Though Oberon/F makes great use of inheritance internally 

(eg. Stores -> Models -> TextModels) it strictly controls 

external inheritance to preserve extensibility, by 

imposing the classic separation of interface from 

implementation. Many modules deliberately don't export 

concrete types used in their interface, to prevent 

application programmers from extending them directly. 

Instead they export a global variable containing a 

'directory object' whose 'New' method allows you merely to 

create instances of a hidden concrete type, together with 

an abstract interface type which you can inherit to 

re-implement extensions of the type. This mechanism 

retains most - though not all - of the power of 

inheritance, but it's necessary to guarantee the future 

extensibility of the program's semantics without running 

into the so-called 'fragile base-class' problem (see 

"Extensible Software Systems " May 1994 Byte).        

In the messy world of PC operating systems the Oberon/F 

approach of simplicity and austerity could hardly be more 

at odds with industry practice. C++ programmers like to 

party, and then use industrial-strength debugging tools 

like BoundsChecker and Purify to clean up the mess 

afterwards - the Oberon programmer expects to catch 90% of 

errors at compile time and most of the remainder by 

careful choice of preconditions. But then, twenty years ago 

who'd heard of Diet Cola....  

   

PRICE: Commercial version -  $350

       Educational version - free.


ADDRESS:

Oberon Microsystems Inc.,

Solothurnerstrasse 45

CH-4053 Basel

Switzerland 

Fax: +41-(0)61-361-3846

Email: oberon@applelink.apple.com

---------------------------------------------------------------

Listing 1

MODULE DickText;

IMPORT TextModels, TextControllers;

  PROCEDURE UpCase*;

  VAR beg, end: LONGINT;

            ch: CHAR;     

             c: TextControllers.Controller;

           buf: TextModels.Model;

             r: TextModels.Reader;

             w: TextModels.Writer;

  BEGIN

    (* determine extent of selected text *)

    c := TextControllers.Focus();

    IF (c # NIL) & c.HasSelection() THEN

      c.GetSelection(beg,end);

      (* make a buffer for upper-case text *)

      buf := TextModels.dir.New(); (* a directory object *)

      w := buf.NewWriter(NIL);

      r := c.text.NewReader(NIL);

      r.SetPos(beg);

      (* process selected text into buffer *)

      r.ReadChar(ch);

      WHILE (r.Pos() <= end) & ~r.eot DO

        IF (ch >= "a") & (ch <= "z")

        THEN ch := CAP(ch) END;

        w.WriteChar(ch);

        r.ReadChar(ch)

      END;

      (* copy buffer back into document *)

      c.text.Delete(beg,end);

      c.text.CopyFrom(beg,buf,0,end-beg);

    END

  END UpCase;

END DickText.