14.4 Module Names and Loading (original) (raw)

14.4 Module Names and Loading🔗

14.4.1 Resolving Module Names🔗

The syntax/modresolve library provides additional operations for resolving and manipulating module names.

The name of a declared module is represented by a resolved module path, which encapsulates either a symbol or a complete filesystem path (see Paths). A symbol normally refers to a predefined module or module declared through reflective evaluation (e.g., eval). A filesystem path normally refers to a module declaration that was loaded on demand via require or other forms.

A module path is a datum that matches the grammar formodule-path for require. A module path is relative to another module.

Returns #t if v is a resolved module path,#f otherwise.

Returns a resolved module path that encapsulates path, where a list path corresponds to a submodule path. If path is a path or starts with a path, the path normally should becleansed (see cleanse-path) and simplified (seesimplify-path, including consulting the file system).

A resolved module path is interned. That is, if tworesolved module path values encapsulate paths that areequal?, then the resolved module path values areeq?.

(resolved-module-path-name module-path)
module-path : resolved-module-path?

Returns the path or symbol encapsulated by a resolved module path. A list result corresponds to a submodule path.

Returns #t if v corresponds to a datum that matches the grammar for module-path for require,#f otherwise. Note that a path (in the sense ofpath?) is a module path.

A parameter that determines the current module name resolver, which manages the conversion from other kinds of module references to a resolved module path. For example, when the expander encounters (require module-path) wheremodule-path is not an identifier, then the expander passes'module-path to the module name resolver to obtain a symbol or resolved module path. When such a require appears within a module, the module path resolver is also given the name of the enclosing module, so that a relative reference can be converted to an absolute symbol or resolved module path.

The default module name resolver usescollection-file-path to convert lib and symbolic-shorthand module paths to filesystem paths. Thecollection-file-path function, in turn, uses thecurrent-library-collection-linksand current-library-collection-paths parameters.

A module name resolver takes two and four arguments:

For the second case, the standard module name resolver keeps a table per module registry containing loaded module name. If a resolved module path is not in the table, and #f is not provided as the fourth argument to the module name resolver, then the name is put into the table and the corresponding file is loaded with a variant ofload/use-compiled that passes the expected module name to thecompiled-load handler.

While loading a file, the default module name resolver sets thecurrent-module-declare-name parameter to the resolved module name (while the compiled-load handler setscurrent-module-declare-source). Also, the defaultmodule name resolver records in a private continuation mark the module being loaded, and it checks whether such a mark already exists; if such a continuation mark does exist in the current continuation, then the exn:fail exception is raised with a message about a dependency cycle.

The default module name resolver cooperates with the defaultcompiled-load handler: on a module-attach notification, bytecode-file information recorded by the compiled-load handlerfor the source namespace’s module registry is transferred to the target namespace’s module registry.

The default module name resolver also maintains a small,module registry-specific cache that maps lib and symbolic module paths to their resolutions. This cache is consulted before checking parameters such as current-library-collection-linksand current-library-collection-paths, so results may “stick” even if those parameter values change. An entry is added to the cache only when the fourth argument to the module name resolver is true (indicating that a module should be loaded) and only when loading succeeds.

Finally, the default module name resolver potentially treats asubmod path specially. If the module path as the first element of the submod form refers to non-existent collection, then instead of raising an exception, the default module name resolver synthesizes an uninterned symbol module name for the resultingresolved module path. This special treatment of submodule paths is consistent with the special treatment of nonexistent submodules by the compiled-load handler, so that module-declared?can be used more readily to check for the existence of a submodule.

Module loading is suppressed (i.e., #f is supplied as a fourth argument to the module name resolver) when resolving module paths insyntax objects (see Syntax Objects). When asyntax object is manipulated, the current namespace might not match the original namespace for the syntax object, and the module should not necessarily be loaded in the current namespace.

For historical reasons, the default module name resolver currently accepts three arguments, in addition to two and four. Three arguments are treated the same as four arguments with the fourth argument as#t, except that an error is also logged. Support for three arguments will be removed in a future version.

The current-module-name-resolver binding is provided asprotected in the sense of protect-out.

Changed in version 6.0.1.12 of package base: Added error logging to the default module name resolver when called with three arguments.
Changed in version 7.0.0.17: Added special treatment of submod forms with a nonexistent collection by the default module name resolver.
Changed in version 8.2.0.4: Changed binding to protected.

A parameter that determines a module name that is used when evaluating a module declaration (when the parameter value is not#f). In that case, the id from the moduledeclaration is ignored, and the parameter’s value is used as the name of the declared module.

When declaring submodules, current-module-declare-namedetermines the name used for the submodule’s root module, while its submodule path relative to the root module is unaffected.

A parameter that determines source information to be associated with a module when evaluating a module declaration. Source information is used in error messages and reflected byvariable-reference->module-source. When the parameter value is #f, the module’s name (as determined bycurrent-module-declare-name) is used as the source name instead of the parameter value.

14.4.2 Compiled Modules and References🔗

While expanding a module declaration, the expander resolves module paths for imports to load module declarations as necessary and to determine imported bindings, but the compiled form of amodule declaration preserves the original module path. Consequently, a compiled module can be moved to another filesystem, where the module name resolver can resolve inter-module references among compiled code.

When a module reference is extracted from compiled form (seemodule-compiled-imports) or from syntax objects in macro expansion (see Syntax Object Content), the module reference is reported in the form of a module path index. A module path indexis a semi-interned (multiple references to the same relative module tend to use the same module path index value, but not always) opaque value that encodes a module path (see module-path?) and either a resolved module path or another module path index to which it is relative.

A module path index that uses both #f for its path and base module path index represents “self”—i.e., the module declaration that was the source of the module path index—and such a module path index can be used as the root for a chain ofmodule path indexes at compile time. For example, when extracting information about an identifier’s binding within a module, if the identifier is bound by a definition within the same module, the identifier’s source module is reported using the “self” module path index. If the identifier is instead defined in a module that is imported via a module path (as opposed to a literal module name), then the identifier’s source module will be reported using a module path index that contains the required module path and the “self” module path index. A “self” module path indexhas a submodule path when the module that it refers to is asubmodule.

A module path index has state. When it is resolved to a resolved module path, then the resolved module path is stored with the module path index. In particular, when a module is loaded, its root module path index is resolved to match the module’s declaration-time name. This resolved path is forgotten, however, in identifiers that the module contributes to the compiled and marshaled form of other modules. The transient nature of resolved names allows the module code to be loaded with a different resolved name than the name when it was compiled.

Two module path index values are equal? when they haveequal? path and base values (even if they have differentresolved values).

Returns #t if v is a module path index,#f otherwise.

Returns a resolved module path for the resolved module name, computing the resolved name (and storing it in mpi) if it has not been computed before.

Resolving a module path index uses the current module name resolver (see current-module-name-resolver). Depending on the kind of module paths encapsulated by mpi, the computed resolved name can depend on the value ofcurrent-load-relative-directory orcurrent-directory. The load? argument is propagated as the last argument to the module name resolver, while thesrc-stx argument is propagated as the next-to-last argument.

Beware that concurrent resolution in namespaces that share a module registry can create race conditions when loading modules. See alsonamespace-call-with-registry-lock.

If mpi represents a “self” (see above) module path that was not created by the expander as already resolved, thenmodule-path-index-resolve raises exn:fail:contractwithout calling the module name resolver.

See also resolve-module-path-index.

Changed in version 6.90.0.16 of package base: Added the load? optional argument.
Changed in version 8.2: Added the src-stx optional argument.

Returns two values: a module path, and a base path—either amodule path index, resolved module path, or#f—to which the first path is relative.

A #f second result means that the path is relative to an unspecified directory (i.e., its resolution depends on the value ofcurrent-load-relative-directory and/orcurrent-directory).

A #f for the first result implies a #f for the second result, and means that mpi represents “self” (see above). Such a module path index may have a non-#fsubmodule path as reported by module-path-index-submodule.

Returns a non-empty list of symbols if mpi is a “self” (see above) module path index that refers to a submodule. The result is always #f if either result of(module-path-index-split mpi) is non-#f.

Combines path, base, and submod to create a new module path index. The path argument can be#f only if base is also #f. Thesubmod argument can be a list only when path andbase are both #f.

Returns #t if v is a compiled moduledeclaration, #f otherwise. See alsocurrent-compile.

Takes a module declaration in compiled form and either gets the module’s declared name (when name is not provided) or returns a revised module declaration with the given name.

The name is a symbol for a top-level module, or a symbol paired with a list of symbols where the list reflects the submodule path to the module starting with the top-level module’s declared name.

Takes a module declaration in compiled form and either gets the module’s submodules (when submodules is not provided) or returns a revised module declaration with the givensubmodules. The non-star? argument determines whether the result or new submodule list corresponds tomodule declarations (when non-star? is true) or module* declarations (when non-star? is #f).

(module-compiled-imports compiled-module-code)
compiled-module-code : compiled-module-expression?

Takes a module declaration in compiled form and returns an association list mapping phase level shifts (where #f corresponds to a shift into the label phase level) to module references for the module’s explicit imports.

(module-compiled-exports compiled-module-code [verbosity])
compiled-module-code : compiled-module-expression?
verbosity : (or/c #f 'defined-names) = #f

Returns two association lists mapping from a combination of phase leveland binding space to exports at the corresponding phase and space. The first association list is for exported variables, and the second is for exported syntax. Beware however, that value bindings re-exported though a rename transformer are in the syntax list instead of the value list. See phase+space?for information on the phase-and-space representation.

Each associated list, which is represented by list? in the result contracts above, more precisely matches the contract

For each element of the list, the leading symbol is the name of the export.

The second part—the list of module path index values, etc.—describes the origin of the exported identifier. If the origin list is null, then the exported identifier is defined in the module. If the exported identifier is re-exported, instead, then the origin list provides information on the import that was re-exported. The origin list has more than one element if the binding was imported multiple times from (possibly) different sources.

The last part, a symbol, is included only if verbosity is'defined-names. In that case, the included symbol is the name of the definition within its defining module (which may be different than the name that is exported).

For each origin, a module path index by itself means that the binding was imported with a phase level shift of 0(i.e., a plain require without for-meta,for-syntax, etc.) into the default binding space (i.e., without for-space), and the imported identifier has the same name as the re-exported name. An origin represented with a list indicates explicitly the import, the phase level plus binding spacewhere the imported identifier is bound (see phase+space? for more information on the representation), the symbolic name of the import as bound in the importing module, and the phase level plusbinding space of the identifier from the exporting module.

Example:

> (module-compiled-exports (compile '(module banana racket/base (require (only-in racket/math pi) (for-syntax racket/base)) (provide pi (rename-out [peel wrapper]) bush cond (for-syntax compile-time)) (define peel pi) (define bush (* 2 pi)) (begin-for-syntax (define compile-time (current-seconds))))) 'defined-names)
'((0 (bush () bush) (pi (#module-path-index:racket/math) pi) (wrapper () peel)) (1 (compile-time () compile-time)))'((0 (cond (#module-path-index:racket/base) cond)))

Changed in version 7.5.0.6 of package base: Added the verbosity argument.
Changed in version 8.2.0.3: Generalized results to phase–space combinations.

Returns an association list mapping phase level values to symbols that represent variables within the module. These definitions are not directly accessible from source, but they are accessible from bytecode, and the order of the symbols in each list corresponds to an order for bytecode access.

Added in version 6.5.0.5 of package base.

Returns information intended to reflect the “language” of the module’s implementation as originally attached to the syntax of the module’s declaration though the 'module-language syntax property. See also module.

If no information is available for the module, the result is#f. Otherwise, the result is (vector mp name val)such that ((dynamic-require mp name) val) should return function that takes two arguments. The function’s arguments are a key for reflected information and a default value. Acceptable keys and the interpretation of results is up to external tools, such as DrRacket. If no information is available for a given key, the result should be the given default value.

See also module->language-info andracket/language-info.

Returns #t if compiled-module-code represents across-phase persistent module, #f otherwise.

Returns the realm of the module represented bycompiled-module-code.

Added in version 8.4.0.2 of package base.

14.4.3 Dynamic Module Access🔗

Because dynamic-require is a procedure, giving a plain S-expression formod the same way as you would for a require expression likely won’t give you expected results. What you need instead is something that evaluates to an S-expression; usingquote is one way to do it.

Dynamically instantiates the module specified by modin the current namespace’s registry at the namespace’s base phase, if it is not yet instantiated. The current module name resolver may load a module declaration to resolve mod(see current-module-name-resolver); the path is resolved relative to current-load-relative-directory and/orcurrent-directory. Beware that concurrent dynamic-requires in namespaces that share a module registry can create race conditions; see also namespace-call-with-registry-lock.

If provided is #f, then the result is #, and the module is not visited (see Module Expansion, Phases, and Visits) or even made available (for on-demand visits) in phases above the base phase.

Examples:

The double quoted ''a evaluates to the root-module-path 'a(see the grammar for require). Using 'a for mod won’t work, because that evaluates to root-module-path a, and the example is not a module installed in a collection. Using a won’t work, because ais an undefined variable.

Declaring (module a ....) within another module, instead of in the read-eval-print loop, would create a submodule. In that case,(dynamic-require ''a #f) would not access the module, because ''adoes not refer to a submodule.

When provided is a symbol, the value of the module’s export with the given name is returned, and still the module is notvisited or made available in higher phases.

Examples:

> (dynamic-require ''b 'dessert)
"gulab jamun"

If the module exports provided as syntax, then a use of the binding is expanded and evaluated in a fresh namespace to which the module is attached, which means that the module is visited in the fresh namespace. The expanded syntax must return a single value.

Examples:

> (dynamic-require ''c 'dessert2)
"nanaimo bar"

If the module has no such exported variable or syntax, thenfail-thunk is called; the default fail-thunk raisesexn:fail:contract. If the variable named by providedis exported protected (see Code Inspectors), then theexn:fail:contract exception is raised.

If provided is 0, then the module isinstantiated but not visited, the same as whenprovided is #f. With 0, however, the module is made available in higher phases.

If provided is #, then the module isvisited but not instantiated (see Module Expansion, Phases, and Visits), and the result is #.

More examples using different module-path grammar expressions are given below:

Example:

> (dynamic-require 'racket/base #f)

Example:

> (dynamic-require (list 'lib "racket/base") #f)

Examples:

> (dynamic-require '(submod 'a b) 'inner-dessert)
"tiramisu"

The last line in the above example could instead have been written as

Example:

> (dynamic-require ((lambda () (list 'submod ''a 'b))) 'inner-dessert)
"tiramisu"

which is equivalent.

Like dynamic-require, but in a phase that is 1more than the namespace’s base phase.

Returns #t if the module indicated by mod isdeclared (but not necessarily instantiated or visited) in the current namespace, #f otherwise.

If load? is #t and mod is not aresolved module path, the module is loaded in the process of resolving mod (as for dynamic-require and other functions). Checking for the declaration of a submodule does not trigger an exception if the submodule cannot be loaded because it does not exist, either within a root module that does exist or because the root module does not exist.

Returns information intended to reflect the “language” of the implementation of mod. If mod is aresolved module path or load? is #f, the module named by mod must be declared (but not necessarilyinstantiated or visited) in the current namespace; otherwise, mod may be loaded (as for dynamic-requireand other functions). The information returned bymodule->language-info is the same as would have been returned by module-compiled-language-info applied to the module’s implementation as compiled code.

A module can be declared by using dynamic-require.

Examples:

> (dynamic-require 'racket/dict (void))
> (module->language-info 'racket/dict)
#f

Like module-compiled-imports, but produces the imports of mod, which must be declared (but not necessarily instantiated or visited) in the current namespace. See module->language-info for an example of declaring an existing module.

Examples:

> (module->imports ''banana)
'((0 #module-path-index:racket/base #module-path-index:racket/math))
(module->exports mod [verbosity])
verbosity : (or/c #f 'defined-names) = #f

Like module-compiled-exports, but produces the exports of mod, which must be declared (but not necessarily instantiated or visited) in the current namespace. See module->language-info for an example of declaring an existing module.

Examples:

> (module->exports ''banana)

Changed in version 7.5.0.6 of package base: Added the verbosity argument.
Changed in version 8.2.0.3: Generalized results to phase–space combinations.

Like module-compiled-indirect-exports, but produces the indirect exports of mod, which must bedeclared (but not necessarily instantiated orvisited) in the current namespace. Seemodule->language-info for an example of declaring an existing module.

Examples:

> (module->indirect-exports ''banana)
'((0 bush))

Added in version 6.5.0.5 of package base.

Like module-compiled-realm, but produces therealm of mod, which must be declared (but not necessarily instantiated or visited) in the current namespace.

Added in version 8.4.0.2 of package base.

Reports whether mod refers to a module that is predefined for the running Racket instance. Predefined modules always have a symbolic resolved module path, and they may be predefined always or specifically within a particular executable (such as one created byraco exe or create-embedding-executable).

14.4.4 Module Cache🔗

The expander keeps a place-local module cache in order to save time while loading modules that have been previously declared.

Clears the place-local module cache.

Added in version 8.4.0.5 of package base.