Using the Module System

Besides containing a program to be run, an Io source files can also contain a module. Such modules are structured like any other Io program. In fact, any Io module is also required to be a Io program, although not necessarily a very interesting one. This also holds the other way, any Io program can be loaded as a module in a different program. Io's module system lets you reuse code and structure programs better by separating concerns while being extremly simple to use and understand.

An Io module is always stored in a separate file with the name modulename.io. Module names, unlike identifiers, are not case sensitive and the corresponding file name is assumed to be entierly lowercase.

Importing Modules

To be able to use continuations declared in a different module the module first needs to be imported into the program. The statements which does this is always found first in a Io source file can look in two different ways. The first way is this:
import module name.
This imports every identifier exported from the module imported. The second way to specify imports looks like:
import module name: list of identifiers.
The list of identifiers is white space separated and can list any number of identifiers with the period marking the end of the list. To import map and take from the module iterator and everything from tuple into a program one would use:
import iterator: map take.
import tuple.
When a module has been imported any continuations declared in it are made available in the program just as if they had been declared in the program source file. So if there're are two continuations, print_foo and NewFoo, declared in the file foo.io, and the module foo is imported, these two continuations can now be used in the importing program by those same names.

If the module imported declares a continuation with the same name as one declared in the program file it will not be imported and so it won't be available in the program. If two modules imported declare continuations with the same name, the continuation from the module listed later in the import statement will be the one which is imported.

The Export Clause

By default everything declared in a module is exported to any module/program which imports it. This frequently isn't desirable and Amalthea provides a way to specify that only certain continuations are to be exported from a module. These continuations then constitute the module's interface. The syntax for doing this is:
export list of identifiers.
An export clause is always situated before any declarations in a Io source file, but after any import clauses. The list of continuation identifiers is white space separated and may contain the names of any continuation declared in the module. It can also contain names of continuations imported from other modules, those continuations are then re-exported. In the export clause you have to specify each continuation to be exported individually, there is no possibility to re-export entire modules. In this way the interface of a module is always defined either by an export statement or by the continuations declared in it, never by the contents of imported modules.

The Main Continuation

As any module is also required to be a well formed program it also contains a main continuation, the entry point of the program. When a Io source file is imported as a module instead of loaded as a program this main continuation is simply ignored. For source files that are only intended as modules rather than to be executed as programs it is to be considered good style if this continuation at least prints out information about the module name and version, and how to run the program it's associated with, if any. Ideally it's also used for unit tests and/or demo code.

The Finer Points of Amalthea Modules

Modules themselves can in turn import other modules in exactly the same way as programs can. Circular imports, where module A imports module B which in turns imports module A, are also allowed. Circularities involving further modules also works without a problem.

When a module is imported Amalthea will try to locate the corresponding Io source file. First the directory where the importing file is located will be searched. After that any subdirectories of this directory will be searched, in an unspecified order. If this also fails to locate the file Amalthea will try to locate the file in the directories set in the environment variable IOLIB or in their subdirectories, in the order mentioned. If the file isn't found an error will be raised. Each module file is loaded into Amalthea once, but several modules with the same name may be loaded if they are located on different paths.