Large products are typically partitioned into many small units that are arranged into layers of abstraction and encapsulation. When well-applied, this style of organization restricts the visibility of program elements so that it is easy to reason about their spheres of influence. For example, if you know that a method
"Internal error:_" is private to a particular module, then you know that it can safely be renamed without having to hunt for references beyond that module; only the module that defined it needs to be searched. Restricting the visibility of program elements makes the task of managing a project with many thousands of data types and operations significantly more tractable.
The private imports section and extended imports section of a module header permit a programmer to fine-tune the visibility of names. This, in turn, allows her to control what messages may be sent by downstream modules. By carefully selecting import specifications across a series of modules, it is possible to tune the visibility of a message to any desired granularity.
It is also possible to tune the visibility of entire modules via a complementary mechanism: module packages. A module package — simply package hereinafter — is a module that contains other modules, called submodules. A package is represented on a file system as a directory whose file name has a
.avail extension. Inside the directory there must be a module whose file name exactly matches the name of the enclosing directory. This module is called the module package representative (or just representative).
Consider the following file system structure:
This is a high-level snapshot of
Avail, the Avail standard library, excerpted for brevity. Each file name that ends with a solidus
(U+002F) is a directory that corresponds to a package; all other file names are regular files that correspond to modules. Only the contents of
Advanced Math.avail/ have been expanded. Inside the
Avail.avail/ directory is an eponymous file; it is likewise the case with
Advanced Math.avail/. These files,
Advanced Math.avail, respectively, are representatives.
A representative is just an ordinary module, but it serves a special role. The contents of a package are only visible to modules recursively contained within the package; they are not visible to modules outside this package. The sole exception to the rule is the representative. Given an import specification that references a package, the compiler or executor resolves the reference not to the directory itself but to its representative. It is typical for the representative to use its extended imports section to re-export names imported from other modules within the package. In this way, the representative "speaks for" the package.
Because of the module resolution process, a dependent module cannot discern the difference between a package and an ordinary module. This is a deliberate design point of Avail. It permits a large module to be refactored into a package containing many smaller modules without affecting any downstream modules.
|‹ Pragmas Section|||||Return to Modules|||||Module Discovery ›|