Oberon || Library || Module Index || Search Engine || Definition || Module

Ulm's Oberon Library:


Services - type-independent definition of extensions


TYPE Object = POINTER TO ObjectRec;
TYPE ObjectRec = RECORD (Disciplines.ObjectRec) END;
TYPE TypeRec = RECORD (Disciplines.ObjectRec) END;
TYPE Service = POINTER TO ServiceRec;
TYPE ServiceRec = RECORD (Disciplines.ObjectRec) END;
TYPE InstallProc = PROCEDURE (object: Object; service: Service);

TYPE LoadModuleProc = PROCEDURE (module: ARRAY OF CHAR) : BOOLEAN; TYPE LoadServiceProc = PROCEDURE (service, for: ARRAY OF CHAR) : BOOLEAN; TYPE LoaderInterface = POINTER TO LoaderInterfaceRec; TYPE LoaderInterfaceRec = RECORD loadModule: LoadModuleProc; loadService: LoadServiceProc; END; PROCEDURE InitLoader(if: LoaderInterface);

PROCEDURE CreateType(VAR type: Type; name, baseName: ARRAY OF CHAR); PROCEDURE InitType(type: Type; name, baseName: ARRAY OF CHAR); PROCEDURE Init(object: Object; type: Type); PROCEDURE GetType(object: Object; VAR type: Type); PROCEDURE GetTypeName(type: Type; VAR name: ARRAY OF CHAR); PROCEDURE GetBaseType(type: Type; VAR baseType: Type); PROCEDURE IsExtensionOf(type, baseType: Type) : BOOLEAN; PROCEDURE SeekType(name: ARRAY OF CHAR; VAR type: Type);

PROCEDURE Create(VAR service: Service; name: ARRAY OF CHAR); PROCEDURE Seek(name: ARRAY OF CHAR; VAR service: Service); PROCEDURE Define(type: Type; service: Service; install: InstallProc); PROCEDURE Install(object: Object; service: Service) : BOOLEAN; PROCEDURE Supported(object: Object; service: Service) : BOOLEAN; PROCEDURE Installed(object: Object; service: Service) : BOOLEAN; PROCEDURE GetSupportedBaseType(object: Object; service: Service; VAR baseType: Type);


Services associates objects which are an extension of Services.Object with types. The types of Services are first class objects unlike the types of the Oberon language which only allow for type tests and the IS operator. Services are created independently of a particular type and then implemented by different implementors for different types and their extensions. This mechanism allows to offer extensions for objects without changing their implementation and without adding object-specific code to modules which are interested in using these extensions. Implementing modules of services may even be loaded dynamically, if supported by Loader.

Type system

Modules which define extensions of Services.Object must call CreateType or InitType during their initialization. The parameters name and baseName are strings which should correspond to the names of the types in dot notation, e.g. "Events.EventType" or "Streams.Stream". If Services.Object is extended directly, "" should be given instead of "Services.Object". Note that PersistentObjects.RegisterType does this already for extensions of PersistentObjects.Object. InitType is an option when an extension of Services.Type has been declared. Later, any object which is created by this module must be initialized by Init to connect objects with their type. Note that PersistentObjects.Init does this already for extensions of PersistentObjects.Object. The type system of Services does not include Services.Object because this type is considered as an abstract type which must not be instantiated.

Based on these initializations a couple of type oriented operations are possible which extend the built-in type test and the IS operator. GetType retrieves the type of the given object. GetTypeName returns the name previously given to CreateType or InitType. GetBaseType returns the base type of a given type. NIL is returned if the type is a direct extension of Services.Object. IsExtensionOf allows to perform a type test. Giving the name of a type (e.g. "Streams.Stream"), SeekType returns the associated type. The empty string (i.e. "") and "Services.Object" must not be given because Services.Object itself is not covered by the type system.

The combination of GetType and IsExtensionOf allows to perform checks at runtime which are similar to type checks for anchored types in Eiffel:

Services.GetType(refObject, refType);
Services.GetType(otherObject, otherType);
IF Services.IsExtensionOf(otherType, refType) THEN
   (* otherObject has a type which extends that of refObject *)

Creating a Service

Services are abstractions which are created independently of a particular type but need type-specific implementations. They are always extensions which are (in principle) not known by the static implementors of a type. Each service abstraction is represented by a module and the name of the service is usually the name of this module. Create is to be called by this module during the initialization.

Additionally, this module usually defines an interface and a per-object initialization procedure which has this interface as parameter. This initialization procedure is then later to be called by service providers if their install interface procedure of Service gets called. The other exported operations of this abstraction should check for a valid interface, and if not yet provided, call Install for this object, which in turn, causes the type-specific service provider to invoke the service-specific per-object initialization procedure.

There is no guarantee, however, that a service provider for a specific type exists. Consequently, each operation of a service abstraction may fail just due to the missing availability of a service provider. This possibility may be checked for by Supported which returns TRUE for the given object when the service abstraction is applicable. Installed returns TRUE if the object is already prepared for the given service.

In some cases there is no necessity for a object-specific initialization to access the service. Then the service abstraction should offer a type-specific initialization procedure which is to be called by service providers during their initialization phase. This type-specific init procedure is then free to attach a discipline to the type which references the interface of the provider. Define may then be called by the service abstraction instead of the service provider with install set to NIL. The operations of the abstraction can now check for the type of an object (by using GetSupportedBaseType) and seek for the interface at the previously attached discipline. GetSupportedBaseType must be used instead of GetType because service offers extend to all extensions of a type (if not overridden by service offers for specific derived types).

Service providers

Implementors of a service for a specific type should always consult the manual page which describes the service abstraction. While usually Define has to be called by the service provider there may exist cases where this is done by the service abstraction.

Define should be called during the initialization phase. The offered service does not only cover the given type but all its extensions, if not overridden by other providers of the same service for more specific types. The install interface procedure gets called once only for each object. Installed allows to test whether install has been called for the given object or not.

Support for dynamic loading

To avoid reference cycles, Services doesn't import Loader but expects Loader to call InitLoader during the startup and to provide some hooks which allow to load dynamically services.


Services does not generate any error events (to avoid a reference cycle problem because Events imports Services). There a couple of assertions which check for various preconditions:

Note that naming conflicts can be easily avoided by adopting the naming conventions, i.e. by prefixing all names with the module name.

Some errors are indicated by returning a NIL-value:


defines the base type of Services.Object
definition of a meta service
interface to dynamic loading of modules
defines an important extension of Services.Object
defines the "RemoteObjects" service

Edited by: borchert, last change: 1996/09/16, revision: 1.3, converted to HTML: 1997/04/28

Oberon || Library || Module Index || Search Engine || Definition || Module