Differences between Common Lisp and Emacs Lisp

This post is part of Living with Emacs Lisp.

1. Motivation

1.1. Emma

Emma has been an Emacs user for a long time. She comes up with lots of questions on Emacs Lisp and she either google them or stackoverflow them. Answers she find sometimes come as a blog post with general Lisp code examples (which are usually Common Lisp code), or a page in Practical Common Lisp or similar.1 So she decides she is going to learn a little bit of Common Lisp so that she can take things from Common Lisp materials and apply them in her Emacs Lisp coding. She may not need to learn it all the way, but she does want to get familiar with pitfalls that come from differences, for example:

In Emacs Lisp,

(member "na" (list "ga" "na" "da")) ; => ("na" "da")

In Common Lisp,

(member "na" (list "ga" "na" "da")) ; => NIL

1.2. Coco

On the other hand, Coco has been a Common Lisp programmer for a long time and this year she is learning Emacs. She finds that she needs to learn differences of Emacs Lisp from Common Lisp that she knows.

This article is for Emma and Coco, but mostly for Emma. Hopefully someone good at Common Lisp will write an article better for Coco and send back a trackback.2

2. Comprehensive?

Because listing all differences in detail would make this post too long and also because I myself is also learning differences along the way, I will try to add additional Common Lisp notes outside of this article to other future articles in Living with Emacs Lisp if possible.

Let’s skip many things that are either completely different between the two Lisps, or things that are completely non-existent in one Lisp. Differences that are most useful to know are usually things that are sort of similar yet not exactly same between two Lisps. For example, yes and no in English usually correspond to yeah and aniyo respectively in Korean, except when they are not, in which case yes corresponds to aniyo and no corresponds to yeah. This kind of difference can get you. Imagine Prime Minister of UK and South Korean President encountering a mysterious giant red button and discussing whether to press that button or not.

3. first sight differences

Common Lisp is case-insensitive (Update: this is incorrect 3) while Emacs Lisp is always case sensitive.

You can visit Lisp Hyperpolyglot to see how the two Lisps look different. To delete the columns you don’t care from the table, use ActiveTable bookmarklet.

To write Emacs Lisp code, you open a file like blahblah.el in Emacs and you edit it in major mode emacs-lisp-mode. To write Common Lisp code, you open a file like blahblah.lisp and you edit it in major mode lisp-mode and SLIME minor mode. See How to install Common Lisp (CLISP, SBCL) and SLIME on MS Windows.

4. data types

4.1. differences in non-collection data types

I’ve read Numbers, Characters, and Strings (Practical Common Lisp) and got three differences out of it:

  • Common Lisp has precise rational numbers and bignums, unlike Emacs.
  • While characters are just numbers in Emacs, they are their own data type in Common Lisp.
  • read syntax for character objects are different

In Common Lisp, this prints character a:

(print #\a)

In Emacs Lisp, this prints a number for character a:

(print ?a)

What is common in both Lisps is:

  • t and nil are used to represent boolean values by convention
  • nil is the only falsy value.

Those may not be the case in some other Lisp dialects.

4.2. differences in collection data types

In both Lisps,

  • there are cons cells, hash tables, vectors.
  • lists are not a true data type and they are simply made of cons cells. For example, when your variable is referring to a list, it is actually referring to the first cons cell (or nil if an empty list).
  • an empty list is simply nil
  • alists (association lists) and plists (property lists) are not true data types and they are simply some kinds of lists.
  • a vector is an ordered collection with O(1) access for every element.
  • sequence is a supertype of vector and list

Some differences include

  • Vectors can be resizable in Common Lisp, unlike in Emacs Lisp.
  • Sequence functions compare elements using eql by default in Common Lisp. In Emacs Lisp, they use equal or eq.
  • copy-seq in Common Lisp is copy-sequence in Emacs Lisp.
  • Some functions that take only lists in Common Lisp can take any sequences in Emacs Lisp. Examples are append and mapcar.

Read syntax for vectors are different. In Common Lisp,

(vector 1 2) ; ==> #(1 2)

In Emacs Lisp,

(vector 1 2) ; => [1 2]

Common Lisp strings are simply vectors specialized to hold characters. Emacs Lisp strings are separate from vectors and they can have text properties associated with them. For example, following Emacs Lisp code takes a string and returns a copy with text properties (italic face):

(propertize "foo" 'face 'italic) ; ⇒ #("foo" 0 3 (face italic))

As you can see, the read syntax for strings with text properties happens to be similar to the read syntax for Common Lisp vectors.

string= and string-equal are synonyms in Emacs Lisp, while the latter is for case-insensitive comparison in Common Lisp.

Let’s see how two Lisps use the term “array”. In Common Lisp, they say that the function make-array can create multidimensional arrays and that vectors are one-dimensional arrays. In Emacs Lisp, they say that arrays are supertype of strings and vectors, and there are no multidimensional arrays. You can see the type relation diagram for Emacs Lisp in Sequences Arrays Vectors (Emacs Lisp reference).

5. buffer local variables

In Emacs, you often work with buffer-local variables which have no counterpart in Common Lisp.

6. lexical scope and dynamic scope

Both Lisps support special variables and lexical scoping (and therefore also lexical closures). Emacs Lisp used to have no support for lexical scoping and then some years ago Miles Bader (snogglethorpe) implemented it.

For difference between lexically scoping and dynamic scoping, you might want to read lexical scoping and dynamic scoping in Emacs Lisp which is an very long old article I wrote. I will write a much shorter article some day, but for now, there’s that.

6.1. special variables

In Common Lisp, global variables are usually declared with defparameter or defvar. The defparameter and defvar make special variables:4

(defparameter *number-of-processes* 10)
(defvar *world* (make-world))

In Emacs Lisp, global variables are usually declared with defvar or defcustom. The defvar and defcustom make special variables.

(defvar xyz-version "1.2.3"
  "XYZ version")
(defcustom xyz-indent-offset 4
  "Default indentation offset for Xyz."
  :group 'xyz
  :type 'integer
  :safe 'integerp)

In both Lisps, special variables are always dynamically bound (dynamic scoping) instead of being lexically bound (lexical scoping).

Also, defconstant in Common Lisp is defconst in Emacs Lisp.

6.2. lexical scoping

By default, Common Lisp is lexically scoped, that is, every variable is lexically scoped except for special variables.

By default, Emacs Lisp files are dynamically scoped, that is, every variable is dynamically scoped.

Optionally, you can have a lexically scoped Emacs Lisp file. Say you wrote my-test.el whose contents is:

;;; -*- lexical-binding: t; -*-

(require 'my-functions) ; for my-repeat

(defun my-insert-stuff ()
  (interactive)
  ;; inserts "1111111111\n2222222222\n3333333333" to current buffer
  (dolist (i (list "1" "2" "3"))
    (my-repeat 10
               (lambda ()
                 (insert i)))
    (insert "\n")))

and also my-functions.el whose contents is:

(defun my-repeat (n func)
  "Calls FUNC repeatedly, N times."
  (dotimes (i n)
    (funcall func)))

(provide 'my-functions)

The my-test.el is a lexically scoped file because of the first line. If you drop that line, the interactive function my-insert-stuff will become broken.

In a lexically scoped Emacs Lisp file, every variable is lexically scoped except for special variables.

6.3. naming convention for lexical variables and special variables

In Emacs Lisp, you should give yellow names to special variables you define. Yellow names are names with at least one hyphen in them. This alone is not enough to prevent collision between local variables and special variables across different emacs lisp files. See invasion of local variables.

In Common Lisp, you should put asterisks around special variable names, this is called the earmuffs convention.

6.4. using setq to declare a global variable

In Common Lisp, you should do that only for REPL use, and only with certain implementations of Common Lisp. If you want to declare a global variable in some code that you need to release or share, you use defvar or defparameter.

In Emacs Lisp, you get to create global variables from setq when you are trying some code examples from some tutorials or examples you come up with. For example, the following is an example code for demonstrating arithmetic operators:

(setq i 100)
(setq j 200)
(setq k 300)

(print (+ i j k))
(print (* i j k))
(print (- i j k))
(print (/ i j k))

If you paste that code into the scratch buffer and run it, you will be creating three global variables. In the current version of Emacs (it’s 24.3 as of now), the code will not make special variables, that is, even though use of i, j, k within that scratch buffer may or may not be dynamically scoped, use of i, j, k in other lexically scoped files continues to be lexically scoped.

What if in a future version of Emacs, running that code creates special variables? Then you must change the code to use yellow names like my-i, my-j, my-k before running the code, otherwise your Emacs session gets broken.

6.5. “odd” behavior of defvar

In both Lisps, defvar assigns a value only when the variable does not have value already. (defcustom in Emacs Lisp is also like that, but defparameter in Common Lisp is not.)

No difference there then, but the usefulness of this odd behavior comes in different ways.

In Emacs Lisp, say Bob wrote oink.el which is a package for the Oink language. Say oink.el code contains this:

(defvar oink-indent-level 3
  "Number of spaces for each indentation step in `oink-mode'")

That 3 is sort of like when you want to provide a default argument value to an optional parameter of a function. If a user of oink.el, say Alice, feels OK with oink-indent-level being 3, the oink mode will use the value 3, but if she prefers a different value, she can write (setq oink-indent-level 2) 5 somewhere in her init file, and then the oink mode will use value 2 and not 3, even if oink.el is loaded sometime after Alice’s init file is loaded.

In Common Lisp, to see when and why to use defvar instead of defparameter, see setq and defvar in lisp – Stack Overflow

7. namespace

In Common Lisp, there are things called packages and they are used for managing namespaces.

In Emacs Lisp, there is no namespace, but there are still things called packages. An Emacs Lisp package is simply a group of Emacs Lisp files bundled in a certain way so that you can install them easily. Some has some ideas for namespaces though: Hatching a plan to add namespaces to EmacsLisp

8. call by sharing

Both Lisps are call-by-sharing, as are Python, Ruby, JavaScript and many interpreted languages. No difference there. More like a difference from C.

The call-by-sharing behavior is a source of many confusions for some Emacs newbies and also Python newbies, and I will write an article on it, but for now they might want to try Online Python Tutor – Visualize program execution.

9. Three equality operators: eq, equal, eql

In both Lisps,

  • eq is for object identity. (eq x y) is true if and only if x and y are the same identical object.
  • equal is for structural similarity. If x and y are numbers or symbols, (equal x y) is true if and only if x and y are of same type with same value. For some (but not all) container types such as cons cells and strings, objects of that type are equal if and only if they are of the same type and corresponding components are equal.
  • For numbers, (eql x y) is true if and only if x and y are equal. For others, true if and only if they are eq.
  • The (= x y) is for comparing numbers

Since nested lists are made of cons cells and because equal compares cons cells by components, it should be easy to see that

(equal (list 1 2 (list 3 4)) (list 1 2 (list 3 4)))

is true in both Lisps.

On the other hand,

(equal (vector 1 2 (vector 3 4)) (vector 1 2 (vector 3 4)))

is true only in Emacs Lisp.

There is also a difference in how signed zeros are treated, but I am not sure knowing that difference is useful.

In Emacs Lisp, eql and eq are somewhat interchangeable in the sense that the only pairs that can be eql without being eq are pairs of floats and you don’t usually use equality operators with floats. What about integers? In Common Lisp, integers can be eql without being eq for obvious reasons6, but that doesn’t happen in Emacs Lisp because Emacs never creates two integers of equal value.

10. functions that use the three equality operators

assoc, delete, member, rassoc, remove use equal in Emacs Lisp, and eql in Common Lisp. In Common Lisp, these functions take keyword arguments and therefore you can use them with alternative equality predicates. In Emacs Lisp, they don’t take keyword arguments, but they have counterparts that use eq instead: assq, delq, memq, rassq, remq. Are there counterparts that use eql instead? No.7 But as I said earlier, eql and eq are somewhat interchangeable in Emacs, so no big deal.

The Emacs cl-lib package provides cl-assoc, cl-delete, cl-member, cl-rassoc, cl-remove which are compatible with Common Lisp functions.

Unlike Emacs Lisp, Common Lisp’s remove may share structure with an argument, and so (sort (remove ...) ..) may not be safe.

11. The cl-lib package

The Emacs cl-lib package implements many of Common Lisp functions. All functions in the package have the common prefix of cl- and you can use them after you load cl-lib.el by running

(require 'cl-lib)

There is an older package which are often simply called cl.el or cl. This package does not prefix its function names. It is still widely used but is now in the process of being replaced by the cl-lib package. If you need to spot use of functions from cl.el in your own code or someone else code, see this article on highlighting cl.el function names in elisp buffers

12. other functions with different behaviors between two Lisps

(/ 10 2 3) is 1 in Emacs Lisp, 5/3 in Common Lisp. (/ 10.0 2 3) and (/ 10 2 3.0) both give float results in both Lisps. (In Emacs Lisp, I recommend you use floor instead of / for integer division with integer result because nobody will get confused by the former’s behavior.)

For comparing numbers, the following code works only in Common Lisp:

(= 1 1 1) ; => T
(< 1 2 3) ; => T
(<= 1 2 3) ; => T

Emacs Lisp’s comparison operators can only take two arguments:

(= 1 1) ; => t
(< 1 2) ; => t
(<= 1 2) ; => t

Update: Starting with Emacs 24.4, comparison operators can now take many arguments.

Both Lisps provide these functions: floor, ceiling, truncate, mod, round. Let’s only check two of them, which I believe is the most often used: floor and mod. (To check all five, see Numerical Functions – Common Lisp Extensions)

In Common Lisp,

(floor 10.1) ; => 10, 0.10000038
(floor 100 3) ; => 33, 1

(mapcar (lambda (x) (mod x 3))
        (list -3 -2 -1 0 1 2 3 4 5))
;; => (0 1 2 0 1 2 0 1 2)

In Emacs Lisp,

(floor 10.1) ; => 10
(floor 100 3) ; => 33
(cl-floor 10.1) ; => (10 0.09999999999999965)
(cl-floor 100 3) ; => (33 1)

(mapcar (lambda (x) (mod x 3))
        (list -3 -2 -1 0 1 2 3 4 5))
;; => (0 1 2 0 1 2 0 1 2)
(mapcar (lambda (x) (cl-mod x 3))
        (list -3 -2 -1 0 1 2 3 4 5))
;; => (0 1 2 0 1 2 0 1 2)

Common Lisp’s floor returns two values. Common Lisp functions can return multiple values, unlike Emacs Lisp. The function cl-floor from the cl-lib package tries to imitate Common Lisp’s floor by returning a list of two values. On the other hand, there seems no difference between the three versions of mod.

The function mapcar in both Lisps can used like this:

(mapcar (lambda (a) (* 2 a))
        (list 0 1 2))
;; => (0 2 4)

Only Common Lisp’s mapcar can take two lists:

(mapcar #'+
        (list 0 1 2)
        (list 0 10 20))
;; => (0 11 22)

Only Emacs Lisp’s mapcar can take a vector:

(mapcar (lambda (a) (* 2 a))
        (vector 0 1 2))

The cl-lib package provides cl-mapcar which is a superset of both.

13. sharp quote and quote on functions

Some ask what is the right one between:

(mapcar 'cdr '((a . b) (c . d) (e . f)))
(mapcar #'cdr '((a . b) (c . d) (e . f)))

Both lines return (b d f) without error in both Lisps. Before going deeper, let’s define a function first.

(defun my-square (x)
  (* x x))

Then in both Lisps,

(my-square 2) ; => 4
((lambda (x) (* x x)) 2) ; => 4

If you run

(dolist (func (list (symbol-function 'my-square)
                    (function my-square)
                    #'my-square
                    (quote my-square)
                    'my-square
                    #'(lambda (x) (* x x))
                    (function (lambda (x) (* x x)))
                    (lambda (x) (* x x))))
  (print (list (mapcar func (list 2 3))
               func)))

you get this output in Emacs Lisp:

((4 9) (lambda (x) (* x x)))
((4 9) my-square)
((4 9) my-square)
((4 9) my-square)
((4 9) my-square)
((4 9) (lambda (x) (* x x)))
((4 9) (lambda (x) (* x x)))
((4 9) (lambda (x) (* x x)))

and you get this in Common Lisp:

((4 9) #<FUNCTION MY-SQUARE>) 
((4 9) #<FUNCTION MY-SQUARE>) 
((4 9) #<FUNCTION MY-SQUARE>) 
((4 9) MY-SQUARE) 
((4 9) MY-SQUARE) 
((4 9) #<FUNCTION (LAMBDA #) {24F7C4AD}>) 
((4 9) #<FUNCTION (LAMBDA #) {24F8332D}>) 
((4 9) #<FUNCTION (LAMBDA #) {24F8A17D}>)

When the definition of my-square is supposed to change, that is when one becomes right and another becomes wrong, depending on what you want to do.

14. cl-lib functions with more features

We’ve gone through some functions which behave in incompatible ways in two Lisps. Now we go through Emacs Lisp functions which are at least one-way compatible with Common Lisp functions of same name in the sense that Common Lisp versions simply add more feature. Of these functions, we will go through just the ones that have cl-lib counterparts.

For sort which is for sorting,

(sort (list 3 2 1) #'<)
;; => (1 2 3)

(cl-sort (list 3 -2 1) #'< :key #'abs)
;; => (1 -2 3)

For functions that generate random numbers,

(random 10) ; random integer in [0,10)

(cl-random 10) ; random integer in [0,10)
(cl-random 1.0) ; random float in [0,1)

For get which is for getting properties, see the relevant entry in Property Lists – Common Lisp Extensions.

For looping constructs dolist and dotimes, the cl-lib counterparts surrounds the loop with an implicit nil block so that you can use cl-return to break out of the loop. The block, return-from, return in Common Lisp corresponds to cl-block, cl-return-from, cl-return in cl-lib. Emacs Lisp programmers who don’t use cl-lib often use catch and throw instead which are also in Common Lisp.

A defun form can specify an optional parameter but only cl-defun can specify a default value for it:

(defun my-next (num &optional step)
  (+ num (or step 1)))
(my-next 10) ; => 11
(my-next 10 2) ; => 12

(cl-defun my-next (num &optional (step 1))
  (+ num step))
(my-next 10) ; => 11
(my-next 10 2) ; => 12

Both defun and cl-defun can define functions of variable number of arguments using &rest. Only cl-defun can specify keyword arguments (using &key). Only cl-defun surrounds the function body in a named block so that you can use cl-return-from to return from the function. Only cl-defun provides destructuring in arguments list.

defmacro cannot use &body which is like &rest, but cl-defmacro can..

There are also less often used stuff like &environment, &whole, &aux which can be only used in cl-defun or cl-defmacro.

15. table of all cl-lib functions

Generate the table by running emacs -q and then evaluating the following code on that clean Emacs session:

(require 'cl-lib)

(let (result sorted-result shortsym shortname name)
  (mapatoms
   (lambda
     (sym)
     (when (fboundp sym)
       (setq name (symbol-name sym))
       (when (and (string-prefix-p "cl-" name)
                  (not (string-prefix-p "cl--" name)))
         (setq shortname (substring name 3))
         (setq shortsym (intern shortname))
         (push (cons (fboundp shortsym) shortname) result)))))
  (setq sorted-result (cl-sort result #'string< :key #'cdr))
  (cl-loop for (bound . shortname) in sorted-result
           do
           (message "%s%s"
                    (if bound "  " "O ")
                    shortname)))
(view-echo-area-messages)

The table will look like this:

O acons
O adjoin
O assert
  assoc
O assoc-if
...

The O in front means that acons, adjoin, assert, assoc-if are not Emacs built-in functions, but they are nevertheless implemented in cl-lib using names with cl- prefix. The O is not in front of assoc and that means that assoc is an Emacs built-in and that its Common Lisp version cl-assoc is defined in cl-lib.

16. lisp macros

In Emacs Lisp, you define a macro that takes a body like this:

(defmacro my-dotimes-1 (num &rest body)
  (declare (indent 1))  ; <--
  `(let ((it 0))
     (while (< it ,num)
       ,@body
       (setq it (1+ it)))))

In Common Lisp, you define it like this:

(defmacro my-dotimes-2 (num &body body) ; <--
  `(let ((it 0))
     (while (< it ,num)
       ,@body
       (setq it (1+ it)))))

If you don’t want that macro to be anaphoric, you replace it with an uninterned symbol from a call to make-symbol (in both Lisps), or gensym (in Common Lisp). The cl-lib package provides cl-gensym.

Modify macros are defined with define-modify-macro or get-setf-expansion in Common Lisp, with cl-callf or cl-callf2 in Emacs Lisp. For examples, see macros – what is to append as push is to cons, in Lisp? – Stack Overflow

Only Common Lisp has reader macros with which you can make your own read syntax stuff.

17. threads

For Common Lisp, see multithreading – How to implement Multi-Threads in Common Lisp – Stack Overflow

Emacs is single threaded as of now. Nevertheless, Nic Ferrier managed to make elnode, a webserver in Emacs Lisp, which makes use of lexical closures (brought to you by Miles Bader), and Steve Yegge made js2-mode8 which parses JavaScript code in background. For a start, you might want to look into idle timers and processes.

Footnotes:

1

such as Let Over Lamda and The Common Lisp cookbook.

2

with a title like “Emacs Lisp for Common Lisp programmers” or similar

3

this is incorrect, as Yuri Albuquerque commented. Read the comment and also see Why is Common Lisp case insensitive? – Stack Overflow

4

Maybe I should mention that the following code example is copied from an answer in http://stackoverflow.com/questions/3855862/setq-and-defvar-in-lisp

5

It’s often the case that she should write (setq-default oink-indent-level 2) instead, or use the customize interface.

6

call-by-sharing reasons

7

There is actually memql which uses eql. I don’t know why only member has the eql counterpart.

8

I recommend using js3-mode instead which is a fork of js2-mode and js-mode

This entry was posted in Emacs, Lisp and tagged , , . Bookmark the permalink.

5 Responses to Differences between Common Lisp and Emacs Lisp

  1. Common Lisp is actually case sensitive. The reader is case insensitive by default, but you can use small case with \ (like ‘\aA will eval to |aA|).

  2. Jisang Yoo says:

    Thank you for your correction. I will update the article soon.

  3. Pingback: Common Lisp versus Emacs Lisp | Irreal

  4. Phil says:

    Regarding #’(lambda …) syntax in Emacs Lisp, you probably want to mention its import for byte compilation and lexical binding. See http://stackoverflow.com/questions/16801396/when-should-emacs-function-syntax-be-used and perhaps also http://stackoverflow.com/questions/1852844/emacs-lisp-difference-between-function-lambda-and-lambda

  5. Pingback: 链接推荐 —— 2013年10月 | 肉山博客 (Wenshan's Blog)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s