Simple Emacs Module System
Emacs Lisp Makefile
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

This is a simple module system for Emacs Lisp, inspired by Nic Ferrier's proposal. It allows short symbol names in the source code but exports the names using the standard elisp-style module prefixes.

To define a module, see define-module. After a define-module, some symbols in the current load file will be renamed. In particular, symbols coming from defvar, defconst, defun and the like will be renamed -- but other symbols will not be. This feature is critical to keeping normal Elisp working, as the Emacs core sometimes requires certain symbol names in APIs.

Note that a private symbol must be seen -- declared with defvar or the like -- before any uses. Otherwise the renamer will not know to rename the use. Normally this is not a problem but you must take care to declare internal functions when you need mutual recursion. You can do this like so:

(declare-internal-function private-function)

When renaming, exported symbols will be given the package prefix, and internal symbols will use the "--" convention.

E.g., consider:

(define-module testmodule :export (somevar))
(defvar somevar nil)
(defvar private nil)
(provide 'testmodule)

This defines a module named testmodule and two variables, an "exported" one named testmodule-somevar, and a "private" one named testmodule--private.

Symbols from other modules can be imported using import-module. Because module boundaries are purely based on symbol naming conventions, you can also "import" from modules that do not use module.el. These modules are called "implicit" modules. Importing a module also requires the feature.

(define-module testmodule)
;; Import some symbols from M.
(import-module M :symbols (a b c))

Sometimes, for an implicit module, the name of the feature and the name of the module prefix differ. In this case you can use the :prefix keyword:

(import-module cl-macs :prefix cl)

A module is closed by calling provide.

This module system doesn't have an explicit notion of submodules. Rather, it piggy-backs on the existing feature of require, that lets a directory separator in the symbol name load a file from a subdirectory:

(require 'feature/subfeature)


The renaming is not perfect. If your code uses intern or otherwise reflects on symbols then you have to be aware of the transforms done by module.el.

Another issue is that autoload cookies aren't rewritten. This seems reasonably hard to fix, since they can refer to any symbol and so the cookie extraction code would have to duplicate the importing logic.