3.1 Modules: module, module*, ... (original) (raw)
3.1 Modules: module, module*, ...🔗ℹ
The module Form in The Racket Guide introduces module.
(module id module-path form ...)
Declares a top-level module or a submodule. For a top-level module, if the current-module-declare-name parameter is set, the parameter value is used for the module name and id is ignored, otherwise (quote id) is the name of the declared module. For a submodule, id is the name of the submodule to be used as an element within a submod module path. A module form is not allowed in an expression contextor internal-definition context.
For a module-like form that works in definition contexts other than the top level or a module body, there’sdefine-package, but using a separate module or submoduleis usually better.
The module-path form must be as for require, and it supplies the initial bindings for the body forms. That is, it is treated like a (require module-path) prefix before theforms, except that the bindings introduced bymodule-path can be shadowed by definitions andrequires in the module body forms.
If a single form is provided, then it is partially expanded in a module-begin context. If the expansion leads to#%plain-module-begin, then the body of the#%plain-module-begin is the body of the module. If partial expansion leads to any other primitive form, then the form is wrapped with #%module-begin using the lexical context of the module body; this identifier must be bound by the initialmodule-path import, and its expansion must produce a#%plain-module-begin to supply the module body. If partial expansion produces a compiled module in the sense ofcompiled-module-expression?, that compiled module is used for the enclosing module (skipping all other expansion and compilation steps), but such a result is allowed only in a compilation mode where syntax-local-compiling-module? produces true and when the current code inspector is the initial one. Finally, if multiple forms are provided, they are wrapped with#%module-begin, as in the case where a singleform does not expand to #%plain-module-begin.
After such wrapping, if any, and before any expansion, an'enclosing-module-name property is attached to the#%module-begin syntax object (seeSyntax Object Properties); the property’s value is a symbol corresponding to id.
Each form is partially expanded (seePartial Expansion) in a module context. Further action depends on the shape of the form:
- If it is a begin form, the sub-forms are flattened out into the module’s body and immediately processed in place of thebegin.
- If it is a define-syntaxes form, then the right-hand side is evaluated (in phase 1), and the binding is immediately installed for further partial expansion within the module. Evaluation of the right-hand side is parameterized to set current-namespace as in let-syntax.
- If it is a begin-for-syntax form, then the body is expanded (in phase 1) and evaluated. Expansion within abegin-for-syntax form proceeds with the same partial-expansion process as for a module body, but in a higher phase, and saving all #%provide forms for all phases until the end of the module’s expansion. Evaluation of the body is parameterized to setcurrent-namespace as in let-syntax.
- If the form is a #%require form, bindings are introduced immediately, and the imported modules are instantiated orvisited as appropriate.
- If the form is a #%provide form, then it is recorded for processing after the rest of the body.
- If the form is a define-values form, then the binding is installed immediately, but the right-hand expression is not expanded further.
- If the form is a module form, then it is immediately expanded and declared for the extent of the current top-level enclosing module’s expansion.
- If the form is a module* form, then it is not expanded further.
- Similarly, if the form is an expression, it is not expanded further.
After all forms have been partially expanded this way, then the remaining expression forms (including those on the right-hand side of a definition) are expanded in an expression context. After all expression forms, #%provide forms are processed in the order in which they appear (independent of phase) in the expanded module. Finally, all module* forms are expanded in order, so that each becomes available for use by subsequent module*forms; the enclosing module itself is also available for use bymodule* submodules.
The scope of all imported identifiers covers the entire module body, except for nested module and module* forms (assuming a non-#f module-path in the latter case). The scope of any identifier defined within the module body similarly covers the entire module body except for such nested moduleand module* forms. The ordering of syntax definitions does not affect the scope of the syntax names; a transformer for A can produce expressions containing B, while the transformer for B produces expressions containing A, regardless of the order of declarations for A and B. However, a syntactic form that produces syntax definitions must be defined before it is used.
No identifier can be imported or defined more than once at anyphase level within a single module, except that a definition via define-values or define-syntaxes can shadow an import via #%require—as long as no preceding#%declare form includes #:require=defined. Every exported identifier must be imported or defined. No expression can refer to a top-level variable. A module* form in which the enclosing module’s bindings are visible (i.e., a nested module* with #f instead of a module-path) can define or import bindings that shadow the enclosing module’s bindings.
The evaluation of a module form does not evaluate the expressions in the body of the module (except sometimes for redeclarations; see Module Redeclarations). Evaluation merely declares a module, whose full name depends both on id or(current-module-declare-name).
A module body is executed only when the module is explicitlyinstantiated via require ordynamic-require. On invocation, imported modules are instantiated in the order in which they are required into the module (although earlier instantiations or transitiverequires can trigger the instantiation of a module before its order within a given module). Then, expressions and definitions are evaluated in order as they appear within the module. Each evaluation of an expression or definition is wrapped with a continuation prompt (see call-with-continuation-prompt) for the default prompt tag and using a prompt handler that re-aborts and propagates its argument to the next enclosing prompt. Each evaluation of a definition is followed, outside of the prompt, by a check that each of the definition’s variables has a value; if the portion of the prompt-delimited continuation that installs values is skipped, then the exn:fail:contract:variable? exception is raised.
Portions of a module body at higher phase levels are delimited similarly to run-time portions. For example, portions of a module within begin-for-syntax are delimited by a continuation prompt both as the module is expanded and when it is visited. The evaluation of a define-syntaxes form is delimited, but unlikedefine-values, there is no check that the syntax definition completed.
Accessing a module-level variable before it is defined signals a run-time error, just like accessing an undefined global variable. If a module (in its fully expanded form) does not contain aset! for an identifier that defined within the module, then the identifier is a constant after it is defined; its value cannot be changed afterward, not even through reflective mechanisms. The compile-enforce-module-constants parameter, however, can be used to disable enforcement of constants.
When a syntax object representing a module form has a'module-language syntax property attached, and when the property value is a vector of three elements where the first is a module path (in the sense of module-path?) and the second is a symbol, then the property value is preserved in the corresponding compiled and/or declared module. The third component of the vector should be printable and readable, so that it can be preserved in marshaled bytecode. The racket/baseand racket languages attach'#(racket/language-info get-info #f) to a moduleform. See also module-compiled-language-info,module->language-info, andracket/language-info.
See also Modules and Module-Level Variables, Module Expansion, Phases, and Visits, andInformation on Expanded Modules.
Example:
Changed in version 6.3 of package base: Changed define-syntaxesand define-values to shadow any preceding import, and dropped the use of 'submodule syntax property values on nestedmodule or module*forms.
(module* id module-path form ...) (module* id #f form ...)
Like module, but only for declaring a submodule within a module, and for submodules that may require the enclosing module.
Instead of a module-path after id, #findicates that all bindings from the enclosing module are visible in the submodule. In that case, begin-for-syntax forms that wrap the module* form shift the phase level of the enclosing module’s bindings relative to the submodule. The macro expander handles such nesting by shifting the phase level of the module* form so that its body starts at phase level 0, expanding, and then reverting the phase level shift; beware that this process can leave syntax objects as'origin syntax property values out-of-sync with the expanded module.
When a module* form has a module-path, the submodule expansion starts by removing the scopes of the enclosing module, the same as the module form. No shifting compensates for any begin-for-syntax forms that may wrap the submodule.
Declares and/or adds to a submodule named id.
Each addition for id is combined in order to form the entire submodule using (module* id #f ....) at the end of the enclosing module. If there is only one module+ for a givenid, then (module+ id form ...) is equivalent to(module* id #f form ...), but still moved to the end of the enclosing module.
A syntax property on the module* form with the key'origin-form-srcloc records the srcloc for every contributing module+ form.
When a module contains multiple submodules declared withmodule+, then the relative order of the initialmodule+ declarations for each submodule determines the relative order of the module* declarations at the end of the enclosing module.
A submodule must not be defined using module+ and module or module*. That is, if a submodule is made of module+ pieces, then it must be made only ofmodule+ pieces.
Changed in version 8.9.0.1 of package base: Added 'origin-form-srcloc syntax property.
(#%module-begin form ...)
The #%module-begin form of racket/base wraps every top-level expression to print non-# results using the print handler as determined by current-print, and it also returns the values after printing. This printing is added as part of the #%module-begin expansion, so the prompt that module itself adds is outside the printing wrapper—and it potentially makes the values returned after printing relevant, because a continuation could be captured and then invoked in a different context.
The #%module-begin form of racket/base also declares a configure-runtime submodule (before any otherform), unless some form is either an immediatemodule or module* form with the nameconfigure-runtime. If a configure-runtime submodule is added, the submodule calls the configure function ofracket/runtime-config.
Like #%module-begin, but without adding aconfigure-runtime submodule.
(#%plain-module-begin form ...)
(#%declare declaration-keyword ...) declaration-keyword = #:cross-phase-persistent | #:empty-namespace #:require=define #:flatten-requires #:unlimited-compile #:unsafe #:realm identifier
Declarations that affect run-time or reflective properties of the module:
- #:cross-phase-persistent — declares the module as cross-phase persistent, and reports a syntax error if the module does not meet the import or syntactic constraints of a cross-phase persistent module.
- #:empty-namespace — declares thatmodule->namespace for this module should produce a namespace with no bindings; limiting namespace support in this way can reduce the lexical information that otherwise must be preserved for the module.
- #:require=define — declares that no subsequent definition immediately with the module body is allowed to shadow a #%require (or require) binding. This declaration does not affect shadowing of a module’s initial imports (i.e., the module’s language).
- #:flatten-requires — declares the performance hint that a compiled form of the module should gather transitive imports into a single, flattened list, which can improve performance when the module is instantiated or when it is attached via namespace-attach-module ornamespace-attach-module-declaration. Flattening imports can be counterproductive, however, when it is applied to multiple modules that are both use by another and that have overlapping transitive-import subtrees.
- #:unlimited-compile — declares that compilation should not fall back to interpreted mode for an especially large module body. Otherwise, a compilation mode is selected based on the size of the module body (as converted to a linklet) and the PLT_CS_COMPILE_LIMIT environment variable (see CS Compilation Modes).
- #:unsafe — declares that the module can be compiled without checks that could triggerexn:fail:contract, and the resulting behavior is unspecified for an evaluation where exn:fail:contract should have been raised; see also Unsafe Operations. For example, a use of car can be compiled as a use ofunsafe-car, and the behavior is unspecified isunsafe-car is applied to a non-pair. The#:unsafe declaration keyword is allowed only when the current code inspector is the initial one. Macros can generate conditionally unsafe code, depending on the expansion context, by expanding to a use of(variable-reference-from-unsafe? (#%variable-reference)).
- #:realm identifier — declares that the module and any procedures within the module are given arealm that is the symbol form of identifier, effectively overriding the value of current-compile-realm.
A #%declare form must appear in a module context or a module-begin context. Eachdeclaration-keyword can be declared at most once within amodule body.
Changed in version 6.3 of package base: Added #:empty-namespace.
Changed in version 7.9.0.5: Added #:unsafe.
Changed in version 8.4.0.2: Added #:realm.
Changed in version 8.6.0.9: Added #:require=define.
Changed in version 8.13.0.4: Added #:flatten-requires.
Changed in version 8.13.0.9: Added #:unlimited-compile.