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

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 its body sequence to serve as the body of the enclosing module, but it also performs additional adjustments to the module body:

  • For each module-body form that is an expression (as opposed to a definition or declaration), #%module_block wraps the expression so that its result values are each printed using Evaluator.current_print. Expressions in places where a nestable declaration is allowed, such as the body of a namespace, as similarly wrapped for printing—but not expressions in other definition contexts, such as in a fun or block body.

  • The #%module_block form 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}.

The module_block form is ilke #%module_block, but it supports configuration of the extra behaviors by #%module_block.

declaration

module_block:

  option

  ...

  body

  ...

 

option

 = 

~effect effect_id

 | 

~effect: effect_id

 | 

~no_added_submodules

Like #%module_block, but with options that affect how the module body is treated.

If an ~effect option provides an effect_id, then effect_id is prefixed on every form where a nestable declaration is allowed by the form is not a definition or declaration. The binding of effect_id itself does not need to be an expression form. If no effect_id is provided, the default causes expression results to be printed as by #%module_block.

If the ~no_added_modules is provided, then no submodules are automatically declared. Otherwise, submodules are potentially added to the module body in the same way as by #%module_block.

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