An analysis by Aaron W. Hsu
Please note that these are just ideas and a tentative proposal. More discussion and debate may reveal a more preferable course of action.
One of the biggest issues I think the Working Groups face is how we deal with modules. I have argued that a syntactic module system is sufficient. While I have gone back and forth on this issue, the more and more I discuss things, the more it seems that making modules syntax instead of a sort of out-of-band library form as R6RS has real merit. Moreover, I believe that all of my previous concerns about packaging system concerns are properly answerable (discussions have yielded convincing enough arguments for their implementability) provided that we agree that all libraries that are useful to use are those which have terminating expansions.
What are the needs of a module system? What is a module system? At its heart a module system is a means of abstracting and hiding code from other code that interacts with a given body of code via a specific set of usually limited bindings. These bindings are both syntax and run-time variables. They allow for better syntactic abstraction and are essentially forms for controlling scope and visibility for both run-time and expansion time bindings.
Java's packaging format, Scheme48's module system, and R6RS' library format are arguably forms of static, out-of-band systems. R6RS however, suffers from requiring evaluation of the source code. PLT has units, and Chez Scheme has its module format, the former being an example of run-time modules (a la ML's functors), and the later being an example of syntactic modules.
There are three interesting module systems I would like to examine. R6RS and Scheme48 modules are relatively static, while Chez Scheme modules presents a fairly different bent. R6RS libraries are a half-in half-out sort of part of the language. They are not language forms in the sense that any macro may generate them. However, there is not built in standard means of separating a code's implementation from its interface. Thus, in R6RS libraries, you must include the code along with the interface to the code in a single top-level form that has a special meaning to implementations. Scheme48's module system is a little more outside of the system in that it has a separate means of defining interface and implementation of an interface, and is almost a mini-language or packaging system that happens to reference or potentially embed some code. Chez Scheme's module system is a syntactic form that is used by the expander to control visibility of bindings. It support separate compilation, but does not support separate interfaces and implementation by default. However, because Chez Scheme's modules do not suffer from the top-level only status of R6RS libraries, it is possible to extend Chez Scheme's modules to support the separation of interface from implementation. In fact, it is possible to use modules in any sort of macro expansion in many interesting ways.
Another interesting point of R6RS libraries is their use of implicit exports. Because macro bindings in the export form of an R6RS library are not marked as syntax explicitly, it is almost impossible for an implementation to statically analyze what additional bindings must be visible to the outside world in the case that the given exported macro expands to these definitions. This makes it very difficult for implementations to identify certain code in a library as unused, and hence, eliminate it upon compilation, resulting in potentially much smaller compiled files. Implicit exports do not see very widespread support, and indeed, R6RS libraries are the only place where I am aware that they see popular use.
The following proposal is based on the Chez Scheme module form.
module ---> (module [library-name] ( export-spec ...) definitions ... expressions ...)
import ---> ([import | import-only] import-spec ...)
library-name ---> identifier
export-spec ---> identifier | (identifier ...)
import-spec ---> library-name
| (only import-spec identifier ...)
| (except import-spec identifier ...)
| (add-prefix import-spec identifier)
| (drop-prefix import-spec identifier)
| (alias import-spec (identifier1 identifier2) ...)
| (rename import-spec (identifier1 identifier2) ...)
Please see the Chez Scheme User's Guide Version 8 for more information about the currently proposed semantics.
The module form is significantly simpler than R6RS' module form, but is capable of expressing the same sorts of abstractions. It is easier to compile, extensible, supports separate compilation and phase separation. It is possible for an implementation to support other features that are desirable from other module systems as well, such as evaluating code inside the environment of a module, or grabing the exported environment of a module.
Oscar Waddell and R. Kent Dybvig, Extending the scope of syntactic abstraction. Conference Record of POPL'99: The 26th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages. January 1999
The benefits of module systems and lexically scoped syntactic abstraction (macro) facilities are well-established in the literature. This paper presents a system that seamlessly integrates modules and lexically scoped macros. The system is fully static, permits mutually recursive modules, and supports separate compilation. We show that more dynamic module facilities are easily implemented at the source level in the extended language supported by the system.