moar articles
Tweet
Follow @nicferrier

Tips on Emacs Lisp programming

I think EmacsLisp is getting to be a great application base, a really good language and environment to write programs in, not just a fancy editor. A number of people seem to agree and are trying it out.

Here's some tips and tricks distilled from my 15 years of using EmacsLisp to help budding Lisp hackers in Emacs.

Do use a modern Emacs

The latest version of Emacs is 24. It's not added to a whole lot of operating system repositories yet but for Debian and Ubuntu you can get it easily by using this repository or PPA at http://emacs.naquadah.org/.

Using the latest version will give you access to lexical scope, built in packaging and lots more goodness.

I am working on a yum equivalent of that APT repository. Donating might make that quicker.

Cut. And also paste

You don't have to have a reusable module for everything, it's ok to cut and paste code sometimes.

There is a massive load of EmacsLisp on github which you can look at and copy.

There's a wealth of code out there, use it

There are Emacs librarys for OAuth (and Oauth2, in ELPA) and for talking to Org Mode and for writing IRC bots or interfacing to PostgreSQL or MySQL or MongoDB. Talking to HTTP and SMTP and handling and parsing XML is built into Emacs. Building parsers and things that understand data definition languages in all sorts of formats is also well covered in EmacsLisp.

Basically, pretty much everything you could want to do as a programmer is there. Sometimes it's not packaged very well, but that's coming.

Use name based namespaces

EmacsLisp does not have a module system. Many people call this a serious weakness but in my experience it's easy to work around it.

There is a heirarchy you should follow:

Given this heirarchy we can adopt some simple but consistent rules:

(defun packagename-module-function (args)
  ...)
(defun packagename-function (args)
  ...)
(defun packagename--function (args)
  ...)
(defmacro with-package-module-thing (...)
  )

Understand packages and autoloads

Autoloads allow lazy loading of EmacsLisp library code. This is basically how they work:

Do use CL

Emacs core has always suggested not requiring cl or using:

(eval-when-compile (require 'cl))

If you are writing code to go into Emacs then that's still valid, but for your own code? Just require cl, it has so many useful extensions, such as loop and dotimes and merge and lots, lots more.

Do write tests

ERT is included in Emacs 24 and provides a good way of writing tests.

You can even use my fakir library to mock tricky bits of Emacs like processes or files.

It's best to write one module of tests for each module of code. A project with a lot of tests is Elnode. Each test module is named after the module that it tests which seems like more good advice.

Do write function docs

ElDoc is really useful when you're writing EmacsLisp but it only works when you have documentation. Try and write good documentation.

You can use my wikidoc program to make HTML documentation from function and variable doc.

Write command scripts with EmacsLisp

Shell scripts are always quick and easy but sometimes you want a program to do a little more, shell becomes unwieldy fast and you want to switch to a proper programming language. EmacsLisp can do this pretty well, here's an example I've used in my blog before:

:;exec emacs -batch -Q -l "$0" -f main "$@"
(require 'cl)
(toggle-debug-on-error)
(defun main ()
  (interactive)
  (destructuring-bind (package &optional elpa-parent) command-line-args-left
    ;; Make the elpa dir for this if we need to.
    (when (and elpa-parent
               (not (file-exists-p elpa-parent)))
      (make-directory elpa-parent t))
    ;; Package stuff
    (setq package-user-dir
          (concat
           (or (concat elpa-parent "/")
               user-emacs-directory)
           ".elpa"))
    (setq package-archives
          '(("gnu" . "http://elpa.gnu.org/packages/")
            ("marmalade" . "http://marmalade-repo.org/packages/")))
    (package-initialize)
    (package-refresh-contents)
    (if (and (file-exists-p (expand-file-name package))
             (not (file-directory-p (expand-file-name package))))
        (package-install-file (expand-file-name package))
        ;; Else must just be a package
        (package-install (intern package)))))

;; End

The first line is what does the magic of making Emacs run the script in batch mode (no windows). Note that what you want to do with the script in that bang line is pretty flexible:

:;exec emacs -batch -Q -l "$0" -f main "$@"

main is the function to call and the $@ is of course shell for the arguments.

Emacs is very powerful at file manipulation, it's buffer mechanism is very useful for certain programming tasks that may be very difficult in shell.

More on scripts in the EmacsWiki.

It's not weird to use Object Orientation in EmacsLisp

Object Oriented coding is suffering a bit of a backlash in some circles but it's still very useful in lots of cicrumstances, where you are trying to declare a category of things that are quite complex for example.

CommonLisp has CLOS, a very comprehensive Object Orientation programming API and EmacsLisp has EIEIO, an implementation of CLOS.

Here's a trivial example of EmacsLisp classes and methods:

(defclass some-userc nil
  ((id
    :initarg :id
    :initform (lambda () (some-user--make-uuid))
    :documentation "The id of the person")
   (name
    :type string
    :initarg :name
    :initform ""
    :documentation "Name of the person"))
  "A user record.")

(defun some-user--make-uuid () ; functions can be used by constructors
  "1213243")

(defmethod some-user-greeting ((user some-userc) ; this is a type specifier
                               &optional daytime)
  "Methods are functions and have docstrings."
  (if daytime
    (message "good morning %s" (oref user name))))

(let ((user (some-userc "nic" :name "nic ferrier"))) ; make a user
  (some-user-greeting user t)) ; call the method

Macro writing needs settings

eval-expression-print-level needs to be set to nil (turned off) so that you can always see what's happening.

Don't write too many macros

Macro use cases are:

Of these only the first is common in most programming, the second is obvious when you need it and the last you should think quite carefully before doing, it's normally for Lisp language hackers, not hackers in Lisp language.

PS That doesn't mean you should never write control flow macros, just think hard before doing it.

Closures are cool but harder to debug

If you need anything more than a tiny callback function then make a tiny callback that calls an external function with the right data:

(let ((x somecapturedthing))
   (lambda (httpcon)
     (real--implementation httpcon x)))

The full function is nearly always private but it can be more easily instrumented for debugging so you can easily see what's going on in that code. It's also useful sometimes to separate stuff out like this temporarily. It's pretty easy to do quickly, it's probably easy enough that you could write some EmacsLisp to do it automatically.

Use the manuals

Emacs has great documentation including about EmacsLisp itself and CL and EIEIO.

The Elisp Cookbook on the EmacsWiki is also a great resource.

Do ask questions

On StackOverflow, reddit or on IRC.

So that's it

These are the things I can think of that people don't know. If you're thinking of looking at a Lisp for your next programming project then I really recommend EmacsLisp, it's a very practical language with lots to recommend it.

Fixes

I got the value of eval-expression-print-level wrong, it should be nil to be turned off, 0 will stop any structure printing. This is now fixed.