This Design Note specifies a syntax and semantics for module defining forms, which further documents the description of modules found in the Dylan book.Dylan Design Notes
Dylan Design Notes: #32: Module Defining Forms (Addition) #32: Module Defining Forms (Addition)
Version 1, January 1994 Copyright (c) 1993-1994, Apple Computer
Within a given module, a variable name refers to at most one variable. It is an error to create or import two or more different variables with the same name in a single module. If a name does refer to a variable, the variable is said to be accessible from the module. Each variable is owned by exactly one module, but it can be accessible from many modules.
Owned variables are created by the create: keyword argument to define-module and in some cases by definitions associated with a module.
Dylan includes two kinds of definitions. Explicit definitions are created by define-constant, define-variable, define-generic-function, and the class name in define-class. Implicit definitions are created by define-method and the slot specifications of define-class.
Definitions are used both to create variables and to provide values for variables. An explicit definition performed on a variable which was not imported creates an owned variable and provides a value for it. An explicit definition performed on a variable which was imported just provides a value for the variable. An implicit definition has the same behavior, but only if there is no explicit definition for the variable. (If there is an explicit definition for the variable, then the implicit definition does not create the variable, nor does it provide the value for it.)
There must be exactly one explicit definition for each module variable, with the exception that the explicit definition can be left out if there are one or more implicit definitions. Any module variable whose value is a generic function can have any number of implicit definitions.
A technique for associating an expression with a module is described in the Design Note #33: Headers for Dylan Source Files (Addition).
Module declarations are expressions. Like other defining forms, module declarations are only allowed at top level or inside of begin. The variable names in module declarations are relative either to the module being declared or to a module that it uses, and thus are not affected by the module declaration's associated module. A module declaration can be associated with any module where define-module has its normal meaning.
Before an expression can be compiled, the module declaration for the module associated with the expression must be compiled and then made available to the development environment in an implementation-defined way.
Macros can expand into module declarations. This happens during compilation of the module declaration.
define-module module-name { module-clause }* [Module Declaration]where each module-clause is either a use clause, a create clause, or an export clause (see below).
This form defines the module with the given name. It describes which modules are used by the module being defined, which variables are imported from the used modules, and which variables are exported by the module being defined.
module-name has the same syntax as identifiers and symbols. Module names are global in scope. Under this proposal, entire programs are compiled as a unit and module names are global to that unit. Though they are not part of this proposal, extensions to allow separate compilation will be considered in the future. The namespace of module names is distinct from that of variables. No variable with the name module-name is created.
(use used-module-name #key import export prefix exclude rename)
used-module-name is the name of a module to be used. By default all exported variables from the used module are imported by the module being defined, under the same name they had in the used module.
When there are multiple use clauses using the same module, the set of imported variables is the union of those specified by all the use clauses. Some variables may be imported under more than one variable name.
The keyword options are used to prevent some variables from being imported, to give some or all variables different names in the new module, and to re-export variables which were imported from a used module. Each of these keyword options applies within the scope of the particular use clause, and does not affect the behavior of other use clauses (even if the other use clauses indicate the same module).
import: ({variable-name | (old-name => new-name) }*) | all
Indicates which variables are to be imported from the module being used. The default is all, meaning that all the variables exported by the used module should be imported. When => appears in an import-option, it specifies both an import and a rename. In other words,
import: (foo => bar)is simply an abbreviation for
import: (foo), rename: (foo => bar)and means exactly the same thing.
exclude: ({variable-name}*)Indicates variables which should not be imported. This keyword can only be used if import: is all. The default for the exclude: keyword is ().
prefix: stringPrepends string to the names of variables as they are imported from the used module. This option can be overridden for a particular variable by using the rename: keyword for that variable. The default value is "".
rename: ({(old-name => new-name)}*)Used to override both the import: keyword and the prefix: keyword. The variables named are imported, regardless of whether the import: keyword indicates they should be imported. old-name indicates the name of the variable in the module being used; new-name indicates the name to be given to the variable in the module being defined. The prefix: keyword of the use clause is ignored for variables specified by the rename: keyword. The default value for the rename: keyword is ().
export: ({variable-name}*) | allSpecifies variables which should be exported from the module being defined. Each of these variables must have been imported by this use clause. variable-name is the name of the variable in the module being defined. It is also the name under which the variable will be exported. It is allowed for the same variable-name to appear more than once, as this is sometimes useful for documentation purposes. all indicates that all the variables imported by this use clause should be exported. The default value for the export: keyword is ().
(export {variable-name }*)This option specifies that the named variables are to be exported from the module being defined. Each variable-name is the name of a variable to export. These variables must be defined by a defining form in the module being defined. It is an error if any of the variables were imported from other modules. It is allowed for the same name to appear more than once, since this is sometimes useful for documentation purposes.
A module create clause has the following syntax:
(create {variable-name }*)This option specifies that the named variables are to be created in and exported from the module being defined. A variable-name is the name of a variable to create and export. These variables must not be defined by a defining form in the module being defined, and they must be defined by a module which uses the module being defined. It is an error if any of the variables were imported from other modules. It is allowed for the same name to appear more than once, since this is sometimes useful for documentation purposes.
define module graphics use dylan; create draw-line, erase-line, invert-line, skew-line frame-rect, fill-rect, erase-rect, invert-rect; end module graphics; define module lines use dylan; use graphics, import: (draw-line, erase-line, invert-line, skew-line); end module lines; define module rectangles use dylan; use graphics, prefix: "graphics$", exclude: (skew-line); end module rectangles; define module dylan-gx use dylan, export: all; use graphics, rename: (skew-line => warp-line), export: all; end module dylan-gx;The modules created by the above module declarations would have access to variables with the following names:
graphics draw-line erase-line invert-line skew-line frame-rect fill-rect erase-rect invert-rect plus all the variables in the Dylan module lines draw-line erase-line invert-line skew-line plus all the variables in the Dylan module rectangles graphics$draw-line graphics$erase-line graphics$invert-line graphics$frame-rect graphics$fill-rect graphics$erase-rect graphics$invert-rect plus all the variables in the Dylan module dylan-gx draw-line erase-line invert-line warp-line frame-rect fill-rect erase-rect invert-rect plus all the variables in the Dylan moduleThe lines and rectangles modules do not export any variables. They are presumably used to provide definitions for the variables created and exported by the graphics modules. The difference between the graphics module and the dylan-gx module is that one variable is renamed, and the dylan-gx module exports the variables which it imports from the dylan module, while the graphics module does not.
define module module-definition module-definition ::= module-name [ module-clauses ] end [ module ] [ module-name ] module-clauses ::= module-clause [ ; ] module-clause ; module-clauses module-clause ::= module-use-clause module-export-clause module-create-clause module-export-clause ::= export variable-names module-create-clause ::= create variable-names module-use-clause ::= use module-name [ , module-use-options ] module-use-options ::= module-use-option module-use-option , module-use-options module-use-option ::= prefix-option import-option exclude-option rename-option export-option prefix-option ::= prefix: string import-option ::= import: all import: import-set import-set ::= ( [ imports ] ) imports ::= import import , imports import ::= variable-name variable-name => variable-name exclude-option ::= exclude: variable-name-set export-option ::= export: all export: variable-name-set rename-option ::= rename: ( [ rename-specs ] ) rename-specs ::= rename-spec rename-spec , rename-specs rename-spec ::= variable-name => variable-name variable-name-set ::= ( [ variable-names ] ) variable-names ::= variable-name variable-name , variable-names variable-name ::= symbol module-name ::= symbol
Next chapter: #33: Headers for Dylan Source Files (Addition)