Modules

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 statement which does this is always found first in a Io source file and looks like this:
import list of module names.
The list of modules is white space separated and can list any number of modules with the period marking the end of the list. To import the modules iterator and tuple into a program one uses the line:
import iterator 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 continuation identifiers.
An export clause is always situated before any declarations in a Io source file, but after any import clause. 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 Importing 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 directory set in the environment variable IOLIB, or in it's subdirectories. 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.