For Development HEAD DRAFTSearch (procedure/syntax/module):

4.13 Modules

This section describes the semantics of Gauche modules and its API. See also Writing Gauche modules, for the conventions Gauche is using for its modules.

For R7RS programs, they are called “libraries” and have different syntax than Gauche modules. See R7RS library form, for the details.


4.13.1 Module semantics

Module is an object that maps symbols onto bindings, and affects the resolution of global variable reference.

Unlike CommonLisp’s packages, which map names to symbols, in Gauche symbols are eq? in principle if two have the same name (except uninterned symbols; see Symbols). However, Gauche’s symbol doesn’t have a ’value’ slot in it. From a given symbol, a module finds its binding that keeps a value. Different modules can associate different bindings to the same symbol, that yield different values.

;; Makes two modules A and B, and defines a global variable 'x' in them
(define-module A (define x 3))
(define-module B (define x 4))

;;  #<symbol 'x'> ---[module A]--> #<binding that has 3>
(with-module A x) ⇒ 3

;;  #<symbol 'x'> ---[module B]--> #<binding that has 4>
(with-module B x) ⇒ 4

A module can export a part or all of its bindings for other module to use. A module can import other modules, and their exported bindings become visible to the module. A module can import any number of modules.

(define-module A
  (export pi)
  (define pi 3.1416))

(define-module B
  (export e)
  (define e 2.71828))

(define-module C
  (import A B))

(select-module C)
(* pi e) ⇒ 8.539748448

A module can also be inherited, that is, you can extend the existing module by inheriting it and adding new bindings and exports. From the new module, all ancestor’s bindings (including non-exported bindings) are visible. (A new module inherits the gauche module by default, which is why the built-in procedures and syntax of gauche are available in the new module). From outside, the new module looks like having all exported bindings of the original module plus the newly defined and exported bindings.

;; Module A defines and exports deg->rad.
;; A binding of pi is not exported.
(define-module A
  (export deg->rad)
  (define pi 3.1416)   ;; not exported
  (define (deg->rad deg) (* deg (/ pi 180))))

;; Module Aprime defines and exports rad->deg.
;; The binding of pi is visible from inside Aprime.
(define-module Aprime
  (extend A)
  (export rad->deg)
  (define (rad->deg rad) (* rad (/ 180 pi))))

;; Module C imports Aprime.
(define-module C
  (import Aprime)
  ;; Here, both deg->rad and rad->deg are visible,
  ;; but pi is not visible.
  )

At any moment of the compilation, there is one "current module" available, and the global variable reference is looked for from the module. If there is a visible binding of the variable, the variable reference is compiled to the access of the binding. If the compiler can’t find a visible binding, it marks the variable reference with the current module, and delays the resolution of binding at the time the variable is actually used. That is, when the variable is referenced at run time, the binding is again looked for from the marked module (not the current module at the run time) and if found, the variable reference code is replaced for the the code to access the binding. If the variable reference is not found even at run time, an ’undefined variable’ error is signaled.

Once the appropriate binding is found for the global variable, the access to the binding is hard-wired in the compiled code and the global variable resolution will never take place again.

The definition special form such as define and define-syntax inserts the binding to the current module. Thus it may shadow the binding of imported or inherited modules.

The resolution of binding of a global variable happens like this. First, the current module is searched. Then, each imported module is taken in the reverse order of import, and searched, including each module’s ancestors. Note that import is not transitive; imported module list is not chased recursively. Finally, ancestors of the current module are searched in order.

This order is important when more than one modules defines the same name and your module imports both. Assuming your module don’t define that name, if you first import a module A then a module B, you’ll see B’s binding.

If you import A, then B, then A again, the last import takes precedence; that is, you’ll see A’s binding.

If two modules you want to use exports bindings of the same name and you want to access both, you can add prefix to either one (or both). See Using modules, for the details.


4.13.2 Modules and libraries

Modules are run-time data structure; you can procedurally create modules with arbitrary names at run-time.

However, most libraries use modules to create their own namespace, so that they can control which bindings to be visible from library users. (This “library” is a general term, broader than R7RS “library”).

Usually a library is provided in the form of one or more Scheme source file(s), so it is convenient to have a convention to map module names to file names, and vice versa; then, you can load a library file and import its module by one action with use macro, for example.

For the time being, Gauche uses a simple rules for this mapping: Module names are organized hierarchically, using period ‘.’ for separator, e.g. gauche.mop.validator. If such a module is requested and doesn’t exist in the current running environment, Gauche maps the module name to a pathname by replacing periods to directory separator, i.e. gauche/mop/validator, and look for gauche/mop/validator.scm in the load paths.

Note that this is just a default behavior. Theoretically, one Scheme source file may contain multiple modules, or one module implementation may span to multiple files. In future, there may be some hook to customize this mapping for special cases. So, when you are writing routines that deal with modules and library files, do not apply the above default rule blindly. Gauche provides two procedures, module-name->path and path->module-name, to do mapping for you (see Module introspection, for details).


4.13.3 Defining and selecting modules

Special Form: define-module name body …

Name must be a symbol. If a module named name does not exist, create one. Then evaluates body sequentially in the module.

Special Form: select-module name

Makes a module named name as the current module. It is an error if no module named name exists.

If select-module is used in the Scheme file, its effect is limited inside the file, i.e. even if you load/require a file that uses select-module internally, the current module of requirer is not affected.

Special Form: with-module name body …

Evaluates body sequentially in the module named name. Returns the last result(s). If no module named name, an error is signaled.

Special Form: current-module

Evaluates to the current module in the compile context. Note that this is a special form, not a function. Module in Gauche is statically determined at compile time.

(define-module foo
  (export get-current-module)
  (define (get-current-module) (module-name (current-module))))

(define-module bar
  (import foo)
  (get-current-module)) ⇒ foo ; not bar

4.13.4 Using modules

Special Form: export spec …

[R7RS base] Makes bindings specified by each spec available to modules that imports the current module.

Each spec can be either one of the following forms, where name and exported-name are symbols.

name

The binding with name is exported.

(rename name exported-name)

The binding with name is exported under an alias exported-name.

Note: In Gauche, export is just a special form you can put in the middle of the program, whereas R7RS defines export as a library declaration, that can only appear immediately below define-library form. See R7RS library form, for the details.

Special Form: export-all

Makes all bindings in the current module available to modules that imports it.

Special Form: import import-spec …

Makes all or some exported bindings in the module specified by import-spec available in the current module. The syntax of import-spec is as follows.

<import-spec> : <module-name>
              | (<module-name> <import-option> ...)

<import-option> : :only (<symbol> ...)
                | :except (<symbol> ...)
                | :rename ((<symbol> <symbol>) ...)
                | :prefix <symbol>

<module-name> : <symbol>

The module named by module-name should exist when the compiler sees this special form.

Imports are not transitive. The modules that module-names are importing are not automatically imported to the current module. This keeps modules’ modularity; a library module can import whatever modules it needs without worrying about polluting the namespace of the user of the module.

import-option can be used to change how the bindings are imported. With :only, only the bindings with the names listed in <symbol> … are imported. With :except, the exported bindings except the ones with the listed names are imported. With :rename, the binding of each name in the first of two-symbol list is renamed to the second of it. With :prefix, the exported bindings are visible with the names that are prefixed by the symbol to the original names. Without import options, all the exported bindings are imported without a prefix.

(define-module M (export x y)
  (define x 1)
  (define y 2)
  (define z 3))

(import M)

x ⇒ 1
z ⇒ error.  z is not exported from M

(import (M :only (y)))

x ⇒ error.  x is not in :only list.

(import (M :except (y)))

y ⇒ error.  y is excluded by :except.

(import (M :prefix M:))

x ⇒ error
M:x ⇒ 1
M:y ⇒ 2

If more than one import option are given, it is processed as the order of appearance. That is, if :prefix comes first, then :only or :except has to list the name with prefix.

Note: R7RS has import form, which has slightly different syntax and semantics. See Three import forms, for the details.

Macro: use name :key only except rename prefix

A convenience macro that combines module imports and on-demand file loading. Basically, (use foo) is equivalent to the following two forms:

(require "foo")
(import foo)

That is, it loads the library file named “foo” (if not yet loaded) which defines a module named foo in it, and then import the module foo into the current module.

The keyword argument only, except, and prefix are passed to import as the import options.

(use srfi.1 :only (iota) :prefix srfi-1:)

(srfi-1:iota 3) ⇒ (0 1 2)

Although the files and modules are orthogonal concept, it is practically convenient to separate files by modules. Gauche doesn’t force you to do so, and you can always use require and import separately. However, all modules provided with Gauche are arranged so that they can be used by use macro.

If a module is too big to fit in one file, you can split them into several subfiles and one main file. The main file defines the module, and either loads, requires, or autoloads subfiles.

Actually, the file pathname of the given module name is obtained by the procedure module-name->path below. The default rule is to replace periods ‘.’ in the name for ‘/’; for example, (use foo.bar.baz) is expanded to:

(require "foo/bar/baz")
(import foo.bar.baz)

This is not very Scheme-ish way, but nevertheless convenient. In future, there may be some mechanism to customize this mapping.

The file to be use’d must have explicit module selection to have any toplevel definitions (usually via define-module/select-module pair or define-library). If you get an error saying “Attempted to create a binding in a sealed module: module: #<module gauche.require-base>”, that’s because the file lacks module selection. See Require and provide, for further discussion.


4.13.5 Module inheritance

The export-import mechanism doesn’t work well in some cases, such as:

You can use module inheritance in these cases.

Macro: extend module-name …

Makes the current module inherit from named modules. The current inheritance information is altered by the inheritance information calculated from given modules.

A new module inherits from gauche module when created. If you put (extend scheme) in that module, for example, the module resets to inherit directly from scheme module that has only bindings defined in R5RS, hence, after the extend form, you can’t use ’import’ or any other gauche-specific bindings in the module.

If a named module is not defined yet, extend tries to load it, using the same convention use macro does.

A module can inherit multiple modules, exactly the same way as a class can inherit from multiple classes. The resolution of order of inheritance needs to be explained a bit.

Each module has a module precedence list, which lists modules in the order of how they are searched. When the module inherits multiple modules, module precedence lists of inherited modules are merged into a single list, keeping the constraints that: (1) if a module A appears before module B in some module precedence list, A has to appear before B in the resulting module precedence list; and (2) if a module A appears before module B in extend form, A has to appear before B in the resulting module precedence list. If no precedence list can be constructed with these constraints, an error is signaled.

For example, suppose you wrote a library in modules mylib.base, mylib.util and mylib.system. You can bundle those modules into one module by creating a module mylib, as follows:

(define-module mylib
  (extend mylib.system mylib.util mylib.base))

The user of your module just says (use mylib) and all exported symbols from three submodules become available.


4.13.6 Module introspection

This subsection lists procedures that operates on modules at run-time. With these procedures you can introspect the modules, create new modules procedurally, or check the existence of certain modules/libraries, for example. However, don’t forget that modules are primarily compile-time structures. Tweaking modules at run-time is only for those who know what they are doing.

Builtin Class: <module>

A module class.

Function: module? obj

Returns true if obj is a module.

Function: find-module name

Returns a module object whose name is a symbol name. If the named module doesn’t exist, #f is returned.

Function: make-module name :key if-exists

Creates and returns a module that has symbol name. If the named module already exists, the behavior is specified by if-exists keyword argument. If it is :error (default), an error is signaled. If it is #f, #f is returned.

Note that creating modules on-the-fly isn’t usually necessary for ordinal scripts, since executing already written program requires modules to be specified by name, i.e. syntax define-module, import, extend, with-module all take module names, not module objects. It is because module are inherently compile-time structures. However, there are some cases that dynamically created modules are useful, especially when the program itself is dynamically created. You can pass a module to eval to compile and evaluate such dynamically created programs in it (see Eval and repl).

You can also pass #f to name to create anonymous module. Anonymous modules can’t be looked up by find-module, nor can be imported or inherited (since import and extend take module names, not modules). It is useful when you want to have a temporary, segregated namespace dynamically—for example, you can create an anonymous module to evaluate code fragments sent from other program, and discards the module when the connection is terminated. Anonymous modules are not registered in the system dictionary and are garbage collected when nobody keeps reference to it.

R7RS provides another way to create a transient module with environment procedure. see scheme.eval - R7RS eval for the details.

Function: all-modules

Returns a list of all named modules. Anonymous modules are not included.

Function: module-name module
Function: module-imports module
Function: module-exports module
Function: module-table module

Accessors of a module object. Returns the name of the module (a symbol), list of imported modules, list of exported symbols, and a hash table that maps symbols to bindings, of the module are returned, respectively.

It is an error to pass a non-module object.

If you want to check if a specific symbol is exported from a module, use module-exports? below instead of taking all exported symbols with module-exports and search from it. It is much faster to use module-exports?.

Function: module-parents module
Function: module-precedence-list module

Returns the information of module inheritance. Module-parents returns the modules module directly inherits from. Module-precedence-list returns the module precedence list of module (see Module inheritance).

Function: module-binds? module symbol

Returns #t if symbol’s global binding is visible from inside module, #f otherwise. That is, if (module-binds? 'M 'v) returns #t, v can be used as a globally bound identifier (either a variable or a syntactic keyword) in the module M. Module must be a module object or a symbol name of an existing module.

This deals with the view from inside module, so it isn’t affected whether the named variable is exported from module, or if so, whether it is renamed on export. If you need to test a variable from the viewpoint external to module, see module-exports? below.

Note: Lisp traditionally has symbol-bound? procedure to check whether a global variable is bound, but we feel the name focuses too much on symbols, whereas global bindings are managed by modules in Gauche. Previous versions of Gauche uses the name global-variable-bound? and it is still kept for the backward compatibility, but we decided on the current name to be clear that it is about modules, and it is not only about variables.

Function: module-exports? module symbol

Returns #t if the binding of symbol is visible from outside module, #f otherwise. That is, if (module-exports? 'M 'v) returns #t, v can be used as a globally bound identifier (either as a variable or a syntactic keyword) in the module that imports module M. Module must be a module object or a symbol name of an existing module.

Unlike module-binds?, this checks the outside appearance of the binding. Suppose you have those modules:

(define-module M
  (export a (rename b bee))
  (define a 1)
  (define b 2)
  (define c 3))

module-binds? concerns how the binding are visible in M. So it returns #t for a, b, and c, but not for bee, as in the following example:

(module-binds? 'M 'a) ⇒ #t
(module-binds? 'M 'b) ⇒ #t
(module-binds? 'M 'c) ⇒ #t

(module-binds? 'M 'bee) ⇒ #f ; renamed export doesn't affect in M

module-exports? concerts how the bindings are visible outside of M. So it returns #t for a and bee, but not for b and c, as in the following example.

(module-exports? 'M 'a) ⇒ #t
(module-exports? 'M 'b) ⇒ #f  ; because of renamed export
(module-exports? 'M 'c) ⇒ #f  ; not exported

(module-exports? 'M 'bee) ⇒ #t  ; external name
Function: module-binding-ref module symbol :optional default

Returns a value globally bound to the symbol inside module. Module must be a module object or a symbol name of an existing module. If there’s no visible global binding inside module for symbol, an error is signaled, unless the default argument is provided, in which case it is returned instead.

This used to be called as global-variable-ref, but we changed the name to be clear that it is module’s operation, and the binding can be not only variables but also syntactic keywords. You can still use the old name but it is deprecated.

Function: global-variable-bound? module symbol
Function: global-variable-ref module symbol :optional default

Deprecated. Old name for module-binds? and module-binding-ref, respectively. Use new names for the new code.

Function: module-name->path symbol

Converts a module name symbol to a fragment of pathname string (which you use for require and provide).

Function: path->module-name string

Reverse function of module-name->path.

If you want to find out specific libraries and/or modules are installed in the system and available from the program, see Operations on libraries.


4.13.7 Predefined modules

Several modules are predefined in Gauche.

Builtin Module: null

This module corresponds to the null environment referred in R5RS. This module contains only syntactic bindings of R5RS syntax.

Builtin Module: scheme

This module contains all the binding of null module, and the binding of procedures defined in R5RS.

Note that if you change the current module to null or scheme by select-module, there will be no way to switch back to other modules, since module-related syntaxes and procedures are not visible from null and scheme modules.

Builtin Module: gauche

This module contains all the bindings of scheme module, plus Gauche specific built-in procedures.

Builtin Module: user

This module is the default module the user code is compiled. all the bindings of gauche module is imported.

Builtin Module: gauche.keyword
Builtin Module: keyword

When Gauche is running with GAUCHE_KEYWORD_IS_SYMBOL mode (default) keywords (symbols beginning with :) is automatically bound to itself in these modules. (see Keywords, for the details.)

The keyword module doesn’t export those bindings, while gauche.keyword does. The former is intended to be used internally; the programmer need to know the latter.

If you use the default module inheritance, you don’t need to use this module, since the keyword module is included in the inheritance chain. If you don’t inherit gauche module, however, importing the gauche.keyword module gives you access to the keywords without quotes. For example, R7RS programs and libraries would require either (import (gauche keyword)) or (import (gauche base)) (the latter inherits gauche.keyword), or you have to quote all keywords.

The following R7RS program imports gauche.base; it makes gauche built-in identifiers, and all self-bound keywords, available:

;; R7RS program
(import (scheme base)
        (gauche base))  ; import gauche builtins and keywords

;; You can use :directory without quote, for it is bound to itself.
(sys-exec "ls" '("ls" "-l") :directory "/")

If you use more sophisticated import tricks, however, keep in mind that keywords are just imported symbols by default. The following code imports Gauche builtin identifiers with prefix gauche/. That causes keywords, imported via inheritance, also get the same prefix; if you don’t want to bother adding prefix to all keywords or quote them, import gauche.keyword separately.

;; R7RS program
(import (scheme base)
        (prefix (gauche base) gauche/) ; use gauche builtin with gauche/ prefix
        (gauche keyword))              ; imports keywords

;; Without importing gauche.keyword,
;; you need to write ':directory
(gauche/sys-exec "ls" '("ls" "-l") :directory "/")
Builtin Module: gauche.require-base

This is a module when use or require load the file. This is not meant to be used directly; just to prevent library files lacking module switching from causing unexpected side effects. See Using modules, for more details.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT