Home‎ > ‎Computing‎ > ‎Byte Articles‎ > ‎

Oberon/F (1994)

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

                    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.
  

Comments