Namespaces

MzScheme supports multiple namespaces for top-level variable bindings, syntax bindings, module imports, and module declarations.

A new namespace is created with the make-namespace procedure, which returns a first-class namespace value. A namespace is used by setting the current-namespace parameter value (see section 7.9.1.5), by providing the namespace to procedures such as eval and eval-syntax. The MzScheme versions of the R5RS procedures scheme-report-environment and null-environment produce namespaces.19

The current namespace is used by many procedures, including eval, load, compile, and expand.20 After an expression is evaled, the global variable references in the expression are permanently attached to a particular namespace, so the current namespace at the time that the code is executed is not used as the namespace for referencing global variables in the expression.

Example:

(define x 'orig) ; define in the original namespace 
;; The following let expression is compiled in the original 
;; namespace, so direct references to x see 'orig. 
(let ([n (make-namespace)]) ; make new namespace 
  (parameterize ([current-namespace n]) 
    (eval '(define x 'new)) ; evals in the new namespace 
    (display x) ; displays 'orig 
    (display (eval 'x)))) ; displays 'new 

A namespace actually encapsulates three top-level environments: one for normal expressions, one for macro transformer expressions, and one for macro templates; see section 12 for more information about the transformer environment, and see section 12.3.4 for more information about the template environment. Module declarations are shared by the environments, but module instances, variable bindings, syntax bindings, and module imports are distinct. More precisely, the transformer environment never contains any syntax bindings, and its variables, module instances, and module imports are distinct from the variables, module instances, and module imports of the normal top-level environment. The template environment contains module imports, only.

Each namespace has a module registry that maps module names to module declarations (see Chapter 5). The module->namespace procedure returns a namespace with the same module registry as the current namespace, but whose environment and bindings correspond to the body of an instantiated module. (This facility is primarily useful for debugging, and its use is limited by the current code inspector; see also section 9.4.)

8.1  Identifier Resolution in Namespaces

Identifier resolution in a namespace's top-level environment, for compilation or expansion, proceeds in two steps. First, the environment determines whether the identifier is mapped to a top-level variable, to syntax, or to a module import (which can be either syntax or a variable). Second, if the identifier is mapped to a top-level variable, then the variable's location is found; if the identifier is mapped to syntax, then the expansion-time binding is found; and if the identifier is mapped to an import, then the source module is consulted.

Importing a variable from a module with require is not the same as defining the variable; the import does not create a new top-level variable in the environment, but instead maps an identifier to the module's variable, in the same way that a syntax definition maps an identifier to a transformer.

Redefining a previously-defined variable is the same as mutating the variable with set!. Rebinding a syntax-bound or import-bound identifier (to syntax or an import) replaces the old binding with the new one for future uses of the environment.

If an identifier is bound to syntax or to an import, then defining the identifier as a variable shadows the syntax or import in future uses of the environment. Similarly, if an identifier is bound to a top-level variable, then binding the identifier to syntax or an import shadows the variable; the variable's value remains unchanged, however, and may be accessible through previously evaluated expressions.

Example:

(define x 5)
(define (f) x)
x ; => 5
(f) ; => 5
(define-syntax x (syntax-rules ()))
x ; =>  bad syntax
(f) ; => 5
(define x 7)
x ; => 7
(f) ; => 7
(module m mzscheme (define x 8) (provide x))
(require m)
x ; => 8
(f) ; => 7

8.2  Initial Namespace

In the stand-alone MzScheme application, the initial namespace's module registry contains declarations for mzscheme and the primitive #%-named modules (see section 5.7). The normal top-level environment of the initial namespace contains imports for all MzScheme syntax, and it contains variable bindings (as opposed to imports) for every built-in procedure and constant. The transformer top-level environment of the initial namespace imports all MzScheme syntax, procedures, and constants.

Applications embedding MzScheme may extend or modify the set of initial bindings, but they will usually only add primitive modules with #%-prefixed names. (MrEd adds #%mred-kernel for its graphical toolbox.)

8.3  Namespace Utilities

(make-namespace [flag-symbol]) creates a new namespace with a new module registry; the flag-symbol is an option that determines the initial bindings in the namespace. The allowed values for flag-symbol are:

(namespace? v) returns #t if v is a namespace value, #f otherwise.

(namespace-symbol->identifier symbol) is similar to datum->syntax-object (see section 12.2.2) restricted to symbols. The lexical context of the resulting identifier corresponds to the top-level environment of the current namespace; the identifier has no source location or properties.

(namespace-variable-value symbol [use-mapping? failure-thunk namespace]) returns a value for symbol in namespace, where namespace defaults to the current namespace. The returned value depends on use-mapping?:

If failure-thunk is provided, namespace-variable-value calls failure-thunk to produce the return value in place of raising an exn:fail:contract:variable or exn:fail:syntax exception.

(namespace-set-variable-value! symbol v [map? namespace]) sets the value of symbol in the top-level environment of namespace (where namespace defaults to the current namespace) defining symbol if it is not already defined. If map? is supplied as true, then the namespace's identifier mapping is also adjusted (see section 8.1) so that symbol maps to the variable. The default value for map? is #f.

(namespace-undefine-variable! symbol namespace) removes the symbol variable, if any, in the top-level environment of the namespace, where namespace defaults to the current namespace. The namespace's identifier mapping is unaffected.

(namespace-mapped-symbols [namespace]) returns a list of all symbols that are mapped to variables, syntax, and imports in namespace, where namespace defaults to the current namespace.

(namespace-require quoted-require-spec) performs the import corresponding to quoted-require-spec in the top-level environment of the current namespace (like a top-level require expression). See also Chapter 5. Module paths in quoted-require-spec are not resolved with respect to any other module, even if the current namespace corresponds to a module body.

(namespace-transformer-require quoted-require-spec) performs the import corresponding to quoted-require-spec in the top-level transformer environment (like a top-level require-for-syntax expression). See also Chapter 5. Module paths in quoted-require-spec are not resolved with respect to any other module, even if the current namespace corresponds to a module body.

(namespace-require/copy quoted-require-spec) is like namespace-require for syntax exported from the module, but exported variables are treated differently: the export's current value is copied to a top-level variable in the current namespace.

(namespace-require/expansion-time quoted-require-spec) is like namespace-require, but only the transformer part of the module is executed. If the required module has not been invoked before, the module's variables remain undefined.

(namespace-attach-module src-namespace module-symbol [dest-namespace]) attaches the instantiated module named module-symbol in src-namespace to the registry of dest-namespace (which is the current namespace if dest-namespace is not supplied), using module-symbol as the module name in dest-namespace. In addition to the module-symbol module itself, every module that it imports (directly or indirectly) is also recorded in the current namespace's registry. If module-symbol is not the name of an instantiated module in src-namespace, or if the name of any module to be attached already has a different declaration or instance in dest-namespace, then the exn:fail:contract exception is raised. The inspector of the module invocation in dest-namespace is the same as inspector of the invocation in src-namespace.

(namespace-unprotect-module inspector module-symbol)namespace changes the inspector for the instance of the module named module-symbol in namespace's registry so that it is controlled by the current code inspector. If namespace is not supplied, it is the current namespace. The given inspector must currently control the invocation of the module in namespace's registry, otherwise the exn:fail:contract exception is raised. See also section 9.4.

(namespace-module-registry namespace) returns the registry of the given namespace. This value is useful only for identification via eq?.

(module->namespace module-path-v) returns a namespace that corresponds to the body of an instantiated module in the current namespace's registry. The returned namespace has the same module registry as the current namespace. Modifying a binding in the namespace changes the binding seen in modules that require the namespace's module. Module paths in a top-level require expression are resolved with respect to the namespace's module. New provide declarations are not allowed. If the current code inspector does not control the invocation of the module in the current namespace's registry, the exn:fail:contract exception is raised; see also section 9.4.

(namespace-syntax-introduce stx) returns a syntax object like stx, except that the current namespace's bindings are included in the syntax object's context (see section 12.3). The additional context is overridden by any existing top-level context in the syntax object, or by any existing or future module context. See section 12.2 for more information about syntax objects.

(module-provide-protected? module-path-index symbol) returns #f if the module declaration for module-path-index defines symbol and exports it unprotected, #t otherwise (which may mean that the symbol corresponds to an unexported definition, a protected export, or an identifier that is not defined at all within the module). The module-path-index argument can be a symbol; see section 12.6.5 for more information on module path indices. Typically, the arguments to module-provide-protected? correspond to the first two elements of a list produced by identifier-binding (see section 12.3).


19 The resulting namespace contains syntax imports for #%app, #%datum, and #%top, because syntax expansion requires them (see section 12.5), but those names are not legal R5RS identifiers.

20 More precisely, the current namespace is used by the evaluation and load handlers, rather than directly by eval and load.