17.3.6 Module-Handling Configuration🔗

Suppose that the file "death-list-5.rkt" contains


#lang racket
(list "O-Ren Ishii"
      "Vernita Green"
      "Elle Driver"

If you require "death-list-5.rkt" directly, then it prints the list in the usual Racket result format:

> (require "death-list-5.rkt")

'("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")

However, if "death-list-5.rkt" is required by a "kiddo.rkt" that is implemented with scheme instead of racket:


#lang scheme
(require "death-list-5.rkt")

then, if you run "kiddo.rkt" file in DrRacket or if you run it directly with racket, "kiddo.rkt" causes "death-list-5.rkt" to print its list in traditional Scheme format, without the leading quote:

("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")

The "kiddo.rkt" example illustrates how the format for printing a result value can depend on the main module of a program instead of the language that is used to implement it.

More broadly, certain features of a language are only invoked when a module written in that language is run directly with racket (as opposed to being imported into another module). One example is result-printing style (as shown above). Another example is REPL behavior. These features are part of what’s called the run-time configuration of a language.

Unlike the syntax-coloring property of a language (as described in Source-Handling Configuration), the run-time configuration is a property of a module per se as opposed to a property of the source text representing the module. For that reason, the run-time configuration for a module needs to be available even if the module is compiled to bytecode form and the source is unavailable. Therefore, run-time configuration cannot be handled by the get-info function we’re exporting from the language’s parser module.

Instead, it will be handled by a new configure-runtime submodule that we’ll add inside the parsed module form. When a module is run directly with racket, racket looks for a configure-runtime submodule. If it exists, racket runs it. But if the module is imported into another module, the 'configure-runtime submodule is ignored. (And if the configure-runtime submodule doesn’t exist, racket just evaluates the module as usual.) That means that the configure-runtime submodule can be used for any special setup tasks that need to happen when the module is run directly.

Going back to the literal language (see Source-Handling Configuration), we can adjust the language so that directly running a literal module causes it to print out its string, while using a literal module in a larger program simply provides data without printing. To make this work, we will need an extra module. (For clarity here, we will implement this module as a separate file. But it could equally well be a submodule of an existing file.)

.... (the main installation or the user’s space)
|- "literal"
   |- "main.rkt"            (with reader submodule)
   |- "show.rkt"            (new)

These changes are implemented in the following revised "literal/main.rkt":


#lang racket
(module reader racket
  (require syntax/strip-context)
  (provide (rename-out [literal-read read]
                       [literal-read-syntax read-syntax])
  (define (literal-read in)
     (literal-read-syntax #f in)))
  (define (literal-read-syntax src in)
    (with-syntax ([str (port->string in)])
       #'(module anything racket
           (module configure-runtime racket
             (require literal/show)
             (show-enabled #t))
           (require literal/show)
           (provide data)
           (define data 'str)
           (show data)))))
  (define (get-info in mod line col pos)
    (lambda (key default)
      (case key
         (dynamic-require 'syntax-color/default-lexer
        [else default]))))

Then the "literal/show.rkt" module must provide the show-enabled parameter and show function:


#lang racket
(provide show show-enabled)
(define show-enabled (make-parameter #f))
(define (show v)
  (when (show-enabled)
    (display v)))

With all of the pieces for literal in place, try running the following variant of "tuvalu.rkt" directly and through a require from another module:


#lang literal

When run directly, we’ll see the result printed like so, because our configure-runtime submodule will have set the show-enabled parameter to #t:


But when imported into another module, printing will be suppressed, because the configure-runtime submodule will not be invoked, and therefore the show-enabled parameter will remain at its default value of #f.