Because of
eval, one program's "compile time" is another program's run-time. Even though they are not first-class, this also applies to
PLT Scheme modules, since they too can be dynamically compiled, loaded and linked. As I've described before,
namespaces are the general construct for managing multiple instances of modules and maintaining their top-level bindings. But I still haven't described how dynamic invocation of modules happens.
Module loading is managed by the system's
module name resolver. The primary responsibility of the module name resolver is to map distinct but equivalent
references to modules into canonical forms. For example, it's possible to refer to the PLT Scheme
string library with either of the two forms:
(lib "string.ss" "scheme")
scheme/string
The standard module name resolver translates these to an absolute path to the module's source file in the filesystem.
The other responsibilities of the standard module name resolver are:
- to ensure that a module is only loaded once,
- to make sure each module is loaded the first time it is needed, and
- to check for and prevent cyclic loading dependencies between modules.
The module name resolver is a pretty low-level part of the PLT system. For the most part, programmers stick to using
dynamic-require to interact with modules dynamically. This dynamically ensures a module is loaded and optionally selects one of its exports by name (by querying its
namespace). But the module name resolver is directly accessible and can be dynamically invoked to ensure a module is loaded and resolve its name to canonical form. The module name resolver is even
configurable, and can be swapped out with a custom resolver--though I have not seen this done in user code.