On this page:
module
pragma
#%module_  block
#{#%module-begin}
8.17.0.6

3.1 Modules and Submodules🔗ℹ

A module is normally written as its own file starting with #lang rhombus or similar. In an interactive context, the module form can declare a module; in that case, the module declared as id can be referenced using self!id.

A submodule is a module that is textually nested in another (sub)module using the module form. Its lifetime might be different than the enclosing (sub)module.

declaration

module id:

  body

  ...

 

declaration

module ~splice id:

  body

  ...

 

declaration

module id ~lang module_path:

  body

  ...

 

declaration

module ~early id ~lang module_path:

  body

  ...

 

declaration

module ~late id ~lang module_path:

  body

  ...

 

declaration

module ~splice id ~lang module_path:

  body

  ...

Creates a submodule within the enclosing module, or declares a module interactively in an interactive context (such as a read-eval-print loop). The module can be accessed with a module path that uses !.

A ~lang is required to declare a module interactively, and ~late or ~splice is not allowed interactively.

When ~lang is not present, then the submodule’s body can refer to bindings in the enclosing module, and the submodule implicitly imports the enclosing module. The enclosing module cannot directly import the submodule, in contrast, since that would create a import cycle. The same id can be declared multiple times this way using module, and all of the body forms for the same id are combined (in the order as the appear) to create one submodule. The expansion of the body forms is delayed until the enclosing module is fully expanded.

When ~lang is present, the module named after ~lang supplies initial bindings for body of the module. In that case, a submodule body cannot refer directly to the bindings of the enclosing module, and no other module in the enclosing module can use the name id.

When ~early is present, or when ~lang is used without ~late or ~splice, then the submodule is defined before the rest of the enclosing module is expanded. The rest of the module can import the submodule using self!id, for example, or the submodule might be used from outside the enclosing module. In the latter case, the enclosing module need not be instantiated to use the submodule.

When ~late or ~splice is used with ~lang for a submodule, then the submodule is expanded only after the enclosing module, similar to use module without ~lang. The submodule can import from the enclosing module using parent, or it can import from sibling submodules using a module path such as parent!id.

Using ~splice without ~lang has no effect, but using it with ~lang means that multiple module definitions are combined, like when not using ~lang. When both ~splice and ~lang are used for a submodule name, then every declaration for that name must use ~splice and ~lang with the same module_path after ~lang.

The body sequence in a module is implicitly wrapped as a #%module_block form, which allows a module that is used as another module’s language to customize the treatment of the other module’s content. The wrapper is on the outside of any import forms that appear in the module body, so #%module_block is useful only as exported by a module that is used as the language for another module. The #%module_block form exported by rhombus adds submodules.

declaration

pragma decl

 

declaration

pragma:

  decl ...

  ...

 

decl

 = 

~unsafe

 | 

~empty_evaluator

Controls properties of a module’s compilation:

  • ~unsafe compiles the module in unsafe mode, where annotation failures trigger unspecified behavior.

  • ~empty_evaluator disables the use of the module’s content for interactive evaluation, which can avoid overhead for the module.

declaration

#%module_block:

  body

  ...

A #%module_block form is implicitly added around the body of a module. A module that implements a language can export its own #%module_block to customize the treatment of a body sequence in any module that uses the exporting module as its language.

The #%module_block form from rhombus mostly expands as its body sequence to serve as the body of the enclosing module, but it also adds submodule declarations depending on ones that are already immediately declared in the body sequence (see Run-Time and Expand-Time Configuration for more information):

  • If a configure_runtime submodule is declared, it is instantiated when the enclosing module is used as the main module for a program.

    The #%module_block form always adds a #{configure-runtime} submodule, which is the configuration submodule name that is recognized at the Racket level. When configure_runtime is declared, then the added #{configure-runtime} submodule depends on the declared submodule as is otherwise empty. Otherwise, the added #{configure-runtime} submodule performs suitable configuration for Rhombus run-time behavior (e.g., a specific formatting for error messages).

  • If a reader submodule is declared, it provides a parser and IDE configuration that applies when the enclosing module is used as a language via #lang. A reader submodule is never added automatically.

    If a configure_expand submodule is not also declared when a reader submodule is declared, then a #{configure-expand} submodule is added to configure expansion-time behavior (e.g., a specific formatting of syntax errors).

    If a configure_expand submodule is declared, then it is expected to export enter_parameterization and exit_parameterization, and those bindings are reexported by an added #{configure-expand} submodule as #{enter-parameterization} and #{exit-parameterization}.

Not for direct use, but exported from rhombus as part of the protocol for a language. See Module ~lang Protocol for more information.