GuileEmacs

For the former contents of this page which were for a large part concerned with the history of all efforts to integrate Guile and Emacs, see GuileEmacsHistory.

Overview

Guile-based Emacs (possibly called “guilemacs” or Guile-Emacs) is a branch of GNU Emacs that replaces Emacs’s own EmacsLisp engine with that of Guile.

The first immediate advantage is that Elisp will execute faster, because Guile uses a compiler tower with many optimization passes and ultimately compiles to Guile VM bytecode, which is more efficient than current Elisp bytecode. In the future, Guile is likely to implement some forms of native JIT as well as AOT compilation as well.

A second advantage is that it will be easier to implement some additional language features for Elisp which the Guile compiler tower and VM are capable of, like a full numeric tower (infinite-sized integers, exact rational numbers, imaginary numbers, etc.), record types (like an improved defstruct), CLOS-like OOP, an FFI, composable continuations, a module system, hygienic macros, multiple-value returns, and threads.

A third advantage is all Guile APIs/libraries becoming available to Elisp code, no matter what language they’re implemented in, because different languages on the Guile VM can inter-operate quite well, especially if they’re both a Lisp. C-implemented functions (“subrs” in Elisp terminology), Elisp functions, Scheme procedures, etc. all compile to the same “procedure” data type, which may appear in Elisp symbols’ function-slots, be bound to Scheme variables, and are otherwise first-class objects in both environments which can be funcalled or applied explicitly or by the language’s normal syntactic way of calling functions. Similarly, other data types are unified between the languages; Elisp integers and exact Scheme integers, inexact Scheme numbers and Elisp floats, Elisp cons cells and Scheme pairs, symbols, etc. are the same data type across the languages. (Strings are an exception though; see below.) Therefore one can generally use a library written in another language as if it were written in the same language.

Lastly, it will become possible to write Emacs extensions in Scheme instead of Elisp, where it’s possible to load the Elisp function and variable namespaces as modules (say with a prefix for each so common names like ‘car’ aren’t overwritten).

Current State

The latest publicly available state of GuileEmacs can be found at BT Templeton's Emacs repository and in their Guile repository. The “wip” branches of both represent the latest state of GuileEmacs and both are necessary to test it. (Build the wip branch of the Guile repo first, then build the wip branch of the Emacs repo with that.)

As of the end of GoogleSummerOfCode 2014, the Elisp engine of Emacs is fully replaced with that of Guile, and most things Just Work™. Some performance regressions remain, especially with programs using dynamic scope. See GuileEmacsTodo.

How to build?

NOTE: The validity of this section could change at any time when the repos get updates.

First you need to clone and build the ‘wip’ branch of this Guile repository. (Not wip-guile or so, just ‘wip’.) This requires all the usual Guile dependencies; see the README file in the repo. A recent version of libgc is best, like 7.4.2. Also recent versions of autotools components. Compilation will take very long, especially for the first few “.go” files. You then need to install this Guile build somewhere where it will be accessible during subsequent compilation of Emacs; you can set the installation root via the ‘--prefix’ option to ./configure.

To make the Guile installation available to subsequent compilation processes, you will probably need to set or augment some environment variables like PATH, PKG_CONFIG_PATH, CPATH, and LIBRARY_PATH. If you just installed it in /usr/local then this is probably not necessary.

Next you clone and build the ‘wip’ branch of this Emacs repository. This requires all the usual Emacs dependencies, though you can disable some features via the ./configure script. (Non-GTK didn’t work for me so let me advise against disabling that.) You need a recent GCC version for this compilation, though 4.7 from Debian stable worked for me.

While building Emacs, you might need to run “make -k” several times if plain “make” fails. I also had to export LD_LIBRARY_PATH=/path/to/libguile during the build, and for launching the resulting emacs executable. /path/to/libguile is, for example, /usr/local/lib if you installed Guile in /usr/local.

A transcript of a successful build of both Guile and Guile-Emacs on Ubuntu 14.04 can be found on pastebin.

Installation script

Dependencies - NicFerrier built on Ubuntu and needed everything from EmacsSnapshotAndDebian:

autoconf automake libtool texinfo build-essential xorg-dev libgtk2.0-dev libjpeg-dev libncurses5-dev libgif-dev libtiff-dev libm17n-dev libpng12-dev librsvg2-dev libotf-dev

as well as these:

flex libgmp-dev libunistring-dev libffi-dev libgc-dev libltdl-dev

Here is a script to build guile and guile-emacs in your home directory:

# Make somewhere to put the source trees
mkdir ~/source
cd ~/source
# Get bipt's guile
git clone --depth 1 -b wip git://git.hcoop.net/git/bpt/guile.git
# Make guile somewhere
cd guile
./autogen.sh
./configure --prefix=$HOME/guile-emacs/guile
make
make install

# Now Emacs
cd ~/source
git clone --depth 1 -b wip git://git.hcoop.net/git/bpt/emacs.git
cd emacs
# These make Emacs' configure stuff find the stuff guile has left
export ACLOCAL_PATH=$HOME/guile-emacs/guile/share/aclocal
export PKG_CONFIG_PATH=$HOME/guile-emacs/guile/lib/pkgconfig
export LD_RUN_PATH=$HOME/guile-emacs/guile/lib
# ... and of course we need to tell Emacs about Guile binaries too...
PATH=$PATH:$HOME/guile-emacs/guile/bin
./autogen.sh 
# ... and build Emacs
./configure --prefix=$HOME/guile-emacs/emacs
make
make install

Warning it takes a long time to compile Guile and a long time to compile Guile-Emacs. This is because Guile-Emacs has to compile every single Elisp file, it doesn’t have the ability to dump a ‘temacs’ like C Emacs does. It took me several hours on a fast, modern laptop in 2014. Also trees will die in the compilation.

Once you’ve compiled and installed you can start Guile-Emacs like so:

$HOME/guile-emacs/emacs

this is a real Emacs remember, so it will try and load your personal config files unless you:

$HOME/guile-emacs/emacs -q

might be worth doing.

Another warning it takes a while to start.

Updating

The Guile and Emacs repositories should normally be updated at the same time. If the Guile repository has changed, you’ll need to rebuild and reinstall it before building a new version of Guile-Emacs to ensure compatibility.

The most convenient way to update is by running ‘git pull --rebase wip’ in each repository. The repositories are rebased themselves from time to time, and the rebase option will prevent the creation of unnecessary merge commits. The rebase option is safe to use for tracking upstream development; if you make local changes, you should read the ‘git pull’ documentation to make sure that its effect is acceptable, and consider doing development in a separate branch.

Dynamic scoping

Elisp defvars are dynamically scoped, as well as let-bound variables when lexical scope isn’t enabled for an Elisp file. These use the same machinery as parameter objects in Scheme. Currently these are not as efficient as they should be, and the presence of buffer-local variables and other weirdities of Elisp binding mechanisms cause additional headaches to Guile in implementing Elisp, which so far leads to a very big performance regression. This will hopefully be addressed shortly.

So can I script Emacs in Scheme already?!

For the Scheme fans who dislike Elisp:

http://i.imgur.com/5DYQbhu.png

(Note: I do NOT endorse using Apple products. The above screenshot being from Mac OS X is an unfortunate coincidence.)

Long-term issues

There seem no long-term issues for pure Elisp users, but the following challenges will face those who want to mix Elisp with Scheme:

Strings

Elisp strings are encoded in an extended UTF-8 format, whereas Guile just uses libunistring. For this reason Elisp strings will for starters be a separate data type from other Guile strings (say coming from Scheme code). This poses no problems to pure Elisp code, but limits one’s ability to seamlessly use Scheme libraries from Elisp, and to write Emacs extensions in Scheme, because one needs to explicitly convert back and forth between Elisp and Scheme strings.

Nil, false, and the empty list

Scheme uses separate objects for the false boolean and empty list (AKA null); Elisp uses nil for both. This poses a challenge in the interoperation of the languages. Guile approaches the issue by internally supporting all three objects (false, null, and nil) but making Elisp and Scheme treat them in such ways that the programmer generally doesn’t notice.

In Elisp, all three objects are (almost) completely indistinguishable, even with ‘eq’, meaning one can ignore the whole issue and all Elisp code continues working as-is. The one way in which the false and null objects might behave different is when ‘print’ing them; it is not set in stone yet what behavior they should have: they might print something other than “nil”, so if they make a round trip like Scheme → Elisp → print → read → Elisp → Scheme, the Scheme code loses no information; or the loss of information could be accepted, making them print “nil” when printed from Elisp code.

In Scheme, nil (which has the syntax #nil) can take the role of both false and null (in ‘if’, ‘not’, null?, etc.), but none of the three are equal? (let alone eqv? or eq?) to each other. That’s because if x and y are equal, and y and z are equal, then x and z must be equal too, but we can’t make false and null equal in Scheme. To elaborate through some code examples: (if #nil 0 1) yields 1, (and (not #nil) (null? #nil)) yields true, and (cons 'foo #nil) yields (foo). This means that everything is fine so long as the user uses ‘if’, ‘not’, null?, etc. instead of comparing equality to literal objects.

A notorious algorithm that won’t work in Scheme without modification is one to find the common tail of two lists that share structure. This algorithm cuts two lists to the same length, then walks them in parallel and does an eq? check on every pair of nodes. Normally this will end at least when the () at the end of both lists is reached (meaning their only common tail is the empty list), but in Scheme code messing with mixed Elisp data one has to separately check for the (and (null? list1-tail) (null? list2-tail)) case at every node (actually testing one of the two is enough because they have the same length), or else one has to canonicalize the lists’s terminating value in advance.

As an additional weirdity, the nil and true objects are also symbols in Elisp, since after all they’re ‘nil’ and ‘t’. They are not symbols in Scheme though, despite being the same objects. The Elisp ‘symbolp’ function and Scheme symbol? procedure simply disagree here, among others which deal with symbols.

Long story short: Elisp is generally unaffected, but don’t freak out if your code prints out some “false” or “null” object where you expected “nil”. If you write Scheme code interacting with Elisp data, make sure to use ‘if’/‘not’/null?/etc. instead of comparing equality to #f or '(). Don’t assume that lists end with equal objects either, which was previously guaranteed because they all ended in null.

Macros

While procedures are shared between the languages, macros are more difficult. Elisp macros are just procedures of course so they could in principle work as unhygienic Scheme macros, and Elisp code goes through the same intermediate language as Scheme so perhaps hygienic Scheme macros could work on Elisp.

The former would probably not work sensibly though, since Elisp function and variable names appearing in the macro output would be inserted into Scheme code where they’re undefined.

The latter might just work. Scheme’s hygienic macros don’t output Scheme code (raw sexprs); they output code in an intermediate language (IL) that can make direct references to bindings in any modules, as well as represent all code concepts that Guile supports in the lower levels. Scheme and Elisp are already both translated to this IL before further compilation or interpretation, so using hygienic macros defined in Scheme on Elisp code would not have any issues; it would simply separately compile (to IL) the Scheme body of the macro template and the Elisp code snippet inputs to the macro, and merge these IL snippets which both reference the correct Scheme and Elisp variable and function bindings. Even identifier inputs to the macro which it binds with ‘let’, like in (syntax-rules () ((with-foo foo body ...) (let ((foo whatever)) body ...))), should conceptually work (lexically bind ‘foo’ for the Elisp code in ‘body’), except that if the macro means to bind ‘foo’ to a procedure then the Elisp code in ‘body’ will need to use ‘funcall’ or ‘apply’ with the variable ‘foo’ since Elisp has a separate function namespace.

It should also be possible to implement a hygienic macro definition form for Elisp, though ‘defmacro’ itself can probably not be made hygienic so using all the currently existing Elisp macros from Scheme remains problematic. They will probably need to be slowly reimplemented as hygienic macros defined in Elisp or Scheme.

See Also

GuileEmacsTodo GuileEmacsHistory


CategoryGuileEmacs CategoryExtensionLanguage EmacsImplementations