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}*) | all
Specifies 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 module
The 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)