0.45+9.2.0.3

8.7 Modules and Macros🔗ℹ

Rhombus’s module system cooperates closely with Rhombus’s macro system (see Expression Macros and Definition and Declaration Macros). For example, in the same way that the rhombus module provides syntax for import and fun, importing other modules can introduce new macro-based syntactic forms—in addition to more traditional kinds of imports, such as functions or constants.

Macros that are defined within a module work the right way when they are imported into another module. Here’s a module that defines and exports noisy_fun, but it does not export the show_arguments function:

module noisy ~lang rhombus:

  import:

    rhombus/meta open

 

  export:

    noisy_fun

 

  defn.macro 'noisy_fun $id($arg, ...): $body; ...':

    'fun $id($arg, ...):

       show_arguments(#'$id, [$arg, ...])

       $body

       ...'

 

  fun show_arguments(name, args):

    println("calling " +& name +& " with arguments " +& args)

The noisy_fun form is like fun for a function definition, but it causes each call to the function to print the arguments that are provided to the function. After importing the noisy module, an example of using noisy_fun to define a function looks like this:

import self!noisy open

 

noisy_fun f(x, y):

  x + y

 

f(1, 2)  // prints "calling f with arguments [1, 2]"

Roughly, the def_noisy form works by replacing

noisy_fun f(x, y):

  x + y

with

fun f(x, y):

  show_arguments(#'f, [x, y])

  x + y

Since show_arguments isn’t exported by the noisy module, however, this literal textual replacement is not quite right. The actual replacement correctly tracks the origin of identifiers like show_arguments, so they can refer to other definitions in the place where the macro is defined—even if those identifiers are not available at the place where the macro is used.

There’s more to the macro and module interaction than identifier binding. The defn.macro form is itself a macro, and it expands to compile-time code that implements the transformation from noisy_fun into fun. The module system keeps track of which code needs to run at compile time and which needs to run normally.