cl: Porting Common Lisp
Appendix C Porting Common Lisp
******************************
This package is meant to be used as an extension to Emacs Lisp, not as
an Emacs implementation of true Common Lisp. Some of the remaining
differences between Emacs Lisp and Common Lisp make it difficult to port
large Common Lisp applications to Emacs. For one, some of the features
in this package are not fully compliant with ANSI or Steele;
Common Lisp Compatibility. But there are also quite a few features
that this package does not provide at all. Here are some major
omissions that you will want to watch out for when bringing Common Lisp
code into Emacs.
• Case-insensitivity. Symbols in Common Lisp are case-insensitive by
default. Some programs refer to a function or variable as ‘foo’ in
one place and ‘Foo’ or ‘FOO’ in another. Emacs Lisp will treat
these as three distinct symbols.
Some Common Lisp code is written entirely in upper case. While
Emacs is happy to let the program’s own functions and variables use
this convention, calls to Lisp builtins like ‘if’ and ‘defun’ will
have to be changed to lower case.
• Lexical scoping. In Common Lisp, function arguments and ‘let’
bindings apply only to references physically within their bodies
(or within macro expansions in their bodies). Traditionally, Emacs
Lisp uses “dynamic scoping” wherein a binding to a variable is
visible even inside functions called from the body.
(elisp)Dynamic Binding. Lexical binding is available since Emacs
24.1, so be sure to set ‘lexical-binding’ to ‘t’ if you need to
emulate this aspect of Common Lisp. (elisp)Lexical
Binding.
Here is an example of a Common Lisp code fragment that would fail
in Emacs Lisp if ‘lexical-binding’ were set to ‘nil’:
(defun map-odd-elements (func list)
(loop for x in list
for flag = t then (not flag)
collect (if flag x (funcall func x))))
(defun add-odd-elements (list x)
(map-odd-elements (lambda (a) (+ a x)) list))
With lexical binding, the two functions’ usages of ‘x’ are
completely independent. With dynamic binding, the binding to ‘x’
made by ‘add-odd-elements’ will have been hidden by the binding in
‘map-odd-elements’ by the time the ‘(+ a x)’ function is called.
Internally, this package uses lexical binding so that such problems
do not occur. Obsolete Lexical Binding, for a description
of the obsolete ‘lexical-let’ form that emulates a Common
Lisp-style lexical binding when dynamic binding is in use.
• Reader macros. Common Lisp includes a second type of macro that
works at the level of individual characters. For example, Common
Lisp implements the quote notation by a reader macro called ‘'’,
whereas Emacs Lisp’s parser just treats quote as a special case.
Some Lisp packages use reader macros to create special syntaxes for
themselves, which the Emacs parser is incapable of reading.
• Other syntactic features. Common Lisp provides a number of
notations beginning with ‘#’ that the Emacs Lisp parser won’t
understand. For example, ‘#| ... |#’ is an alternate comment
notation, and ‘#+lucid (foo)’ tells the parser to ignore the
‘(foo)’ except in Lucid Common Lisp.
• Packages. In Common Lisp, symbols are divided into “packages”.
Symbols that are Lisp built-ins are typically stored in one
package; symbols that are vendor extensions are put in another, and
each application program would have a package for its own symbols.
Certain symbols are “exported” by a package and others are
internal; certain packages “use” or import the exported symbols of
other packages. To access symbols that would not normally be
visible due to this importing and exporting, Common Lisp provides a
syntax like ‘package:symbol’ or ‘package::symbol’.
Emacs Lisp has a single namespace for all interned symbols, and
then uses a naming convention of putting a prefix like ‘cl-’ in
front of the name. Some Emacs packages adopt the Common Lisp-like
convention of using ‘cl:’ or ‘cl::’ as the prefix. However, the
Emacs parser does not understand colons and just treats them as
part of the symbol name. Thus, while ‘mapcar’ and ‘lisp:mapcar’
may refer to the same symbol in Common Lisp, they are totally
distinct in Emacs Lisp. Common Lisp programs that refer to a
symbol by the full name sometimes and the short name other times
will not port cleanly to Emacs.
Emacs Lisp does have a concept of “obarrays”, which are
package-like collections of symbols, but this feature is not strong
enough to be used as a true package mechanism.
• The ‘format’ function is quite different between Common Lisp and
Emacs Lisp. It takes an additional “destination” argument before
the format string. A destination of ‘nil’ means to format to a
string as in Emacs Lisp; a destination of ‘t’ means to write to the
terminal (similar to ‘message’ in Emacs). Also, format control
strings are utterly different; ‘~’ is used instead of ‘%’ to
introduce format codes, and the set of available codes is much
richer. There are no notations like ‘\n’ for string literals;
instead, ‘format’ is used with the “newline” format code, ‘~%’.
More advanced formatting codes provide such features as paragraph
filling, case conversion, and even loops and conditionals.
While it would have been possible to implement most of Common Lisp
‘format’ in this package (under the name ‘cl-format’, of course),
it was not deemed worthwhile. It would have required a huge amount
of code to implement even a decent subset of ‘format’, yet the
functionality it would provide over Emacs Lisp’s ‘format’ would
rarely be useful.
• Vector constants use square brackets in Emacs Lisp, but ‘#(a b c)’
notation in Common Lisp. To further complicate matters, Emacs has
its own ‘#(’ notation for something entirely different—strings with
properties.
• Characters are distinct from integers in Common Lisp. The notation
for character constants is also different: ‘#\A’ in Common Lisp
where Emacs Lisp uses ‘?A’. Also, ‘string=’ and ‘string-equal’ are
synonyms in Emacs Lisp, whereas the latter is case-insensitive in
Common Lisp.
• Data types. Some Common Lisp data types do not exist in Emacs
Lisp. Rational numbers and complex numbers are not present, nor
are large integers (all integers are “fixnums”). All arrays are
one-dimensional. There are no readtables or pathnames; streams are
a set of existing data types rather than a new data type of their
own. Hash tables, random-states, structures, and packages
(obarrays) are built from Lisp vectors or lists rather than being
distinct types.
• The Common Lisp Object System (CLOS) is not implemented, nor is the
Common Lisp Condition System. However, the EIEIO package (
Introduction (eieio)Top.) does implement some CLOS functionality.
• Common Lisp features that are completely redundant with Emacs Lisp
features of a different name generally have not been implemented.
For example, Common Lisp writes ‘defconstant’ where Emacs Lisp uses
‘defconst’. Similarly, ‘make-list’ takes its arguments in
different ways in the two Lisps but does exactly the same thing, so
this package has not bothered to implement a Common Lisp-style
‘make-list’.
• A few more notable Common Lisp features not included in this
package: ‘compiler-let’, ‘prog’, ‘ldb/dpb’, ‘cerror’.
• Recursion. While recursion works in Emacs Lisp just like it does
in Common Lisp, various details of the Emacs Lisp system and
compiler make recursion much less efficient than it is in most
Lisps. Some schools of thought prefer to use recursion in Lisp
over other techniques; they would sum a list of numbers using
something like
(defun sum-list (list)
(if list
(+ (car list) (sum-list (cdr list)))
0))
where a more iteratively-minded programmer might write one of these
forms:
(let ((total 0)) (dolist (x my-list) (incf total x)) total)
(loop for x in my-list sum x)
While this would be mainly a stylistic choice in most Common Lisps,
in Emacs Lisp you should be aware that the iterative forms are much
faster than recursion. Also, Lisp programmers will want to note
that the current Emacs Lisp compiler does not optimize tail
recursion.