Modules, interfaces and implementations

The need to have two modules reference one another often occurs when building systems. In OmniMark V7, it was not possible to do this directly. OmniMark V8 solves this problem by providing a mechanism to split a module into an interface definition module and an implementation module. The interface module contains all of the exported definitions and the implementation module contains the execution code that implements the exported functionality. This division of the module allows users to have modules that directly reference or import one another's definitions. The following example shows a module declaration for an interface:

  ; points.xif
  module interface shared as "points.xif"
  export record point
    field integer x
    field integer y
  export point function 
     plot  (value integer x, 
             value integer y) 
   elsewhere

The implementation of this module might read like this:

  ; points.xmp
  module implements "points.xif"
  export record point
    field integer x initial {0}
    field integer y initial {0}
  
  export point function 
     plot  (value integer x, 
             value integer y)
  as
     local point this-point
     set this-point:x to x
     set this-point:y to y
     return this-point

The standard suffix for a module interface file is .xif (pronounced "zif"). The standard suffix for a module implementation file is xmp (pronounced "chimp").

This example demonstrates how interface and implementation modules are to be used:

  ; main.xom
  import "point.xif" unprefixed
  
  process
    local point my-point
    set my-point to point (7, 12)
  
  import "point.xmp" unprefixed

To use the split modules, you have to include both of them in your program like this:

     import "point.xif" unprefixed
     import "point.xmp" unprefixed
  
    

It is not necessary to have them one after the other, but they both must be imported. The "xif" module must be imported before the first use of one of the exported types, variables or functions occurs.

An interface module can contain:

Only shared modules can be split into interfaces and implementation modules.

An interface module cannot contain code or initial values. Therefore, it cannot contain

  • function bodies,
  • initial values for constants or global variables,
  • initial values for optional function arguments,
  • initial values for record fields, or
  • imports of implementation modules, or combined modules.

The implementation module contains the definitions for everything defined in the interface file, as well as the definitions of any private things that it may require. An implementation module can only export those things declared in its interface module. It is not permitted to extend the interface in any way.

Interface and implementation modules solve the problem of mutually-recursive imports, just like function pre-definitions solve the problem of mutually-recursive functions.