[Oberon] IMPORT Modules: why does order matter?

Andreas Pirklbauer andreas_pirklbauer at yahoo.com
Mon Mar 4 09:12:05 CET 2019

    > One day, the implementor of X and Y decides to do a refactoring, which
    > does not change the interfaces of the modules, but leads to a dependency
    > between those modules: X now imports Y.
    >And suddenly, for no good reason, my module does not compile anymore.

If the “interface" of X does not change, you still be able to compile your module.

See section 16.6.2 of http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.Applications.pdf .

Imported types can by re-exported, and their imports may be hidden.

Consequently, in Oberon, the “interface” of module X has, in fact, two components:

  1) the “explicit" interface, which consists of all objects that are explicitly
     exported by X (i.e. marked with an asterisk in the source text of X). Such
     objects can by constants, types, variables or procedures.

  2) the “hidden” interface, which consists of all those objects that X itself
     has imported from another module Y *and* which are re-exported when X’s
     symbol file is created. Such objects can only be types - for example when
     module X declares a type T which is an extension of a type declared in Y,
     or when X declares a record with a field whose type es declared in Y. Of
     course, not all imported types are re-exported, only some.

There are multiple ways to handle these so-called "re-export conditions". The
approach chosen in FPGA Oberon is to make symbol files “self-contained”,
which means that any types T exported by, imported by X and then re-exported will
be included in the symbol file of X (module name Y, module key of Y, type name T).

The main motivation for this is to prevent the reading of the symbol file of Y when
only X is imported, but not Y (if Y’s symbol file *were* also read, it could trigger an
entire chain reaction of imports). It also means that for N imports exactly N symbol
files need to be read -> this makes import time *linear* in the number of imports).
There have been implementations of Oberon, where symbol files are read
*recursively*. This would also work, but it’s just not done in FPGA Oberon.

So, for a module which imports X, Y, this means:

1) If X does not re-export types imported from Y, its “interface” will not change
   and you can still compile your module (even though, technically speaking,
   X and Y are in the wrong order in the import list - but note: from the importing
   module’s point of view, X and Y are still independent modules, the importing
   module does not “know" that X in facts imports Y).

2) But if module X *does* re-export types imported from Y, then the interface
   of X will also change when X is modified to import Y. And in *that* case, your
   module will need to be recompiled - after changing the import list to Y, X.

More information about the Oberon mailing list