What makes Good ELisp Code?

Rocky Bernstein: rocky@gnu.org

slides: http://rocky.github.com/NYC-Elisp-talk

text: https://github.com/rocky/rocky.github.com/wiki/NYC-Elisp-talk

Glib Answer: Good Code

A full answer would be long. Here I want to focus on:

  • It has short functions/methods
  • It sometimes creates its own logical world if the surrounding environment is deficient
  • In my opinion

    Please don't get unnecessarily creative.

From Emacs C Source

Rather than say the more normal C:

Lisp_Object buffer-live-p(Lisp_Object object) { ...
   add_docstring("non nil if buffer OBJECT ...");
we have:

DEFUN("buffer-live-p", ... 1, 1, 0, doc: /* non-nil if buffer OBJECT has not been killed... */) 
(Lisp_Object object)
  return ((BUFFERP (object) && ! NILP (BVAR (XBUFFER (object), name)))
	  ? Qt : Qnil);

Macro enforces remembering the doc string

C code reads like Lisp code!

return ((BUFFERP (object) && ! NILP (BVAR (XBUFFER (object), name)))
         ? Qt : Qnil);
is roughly in Emacs Lisp:

(if (and (bufferp object) (not (null (BVAR object name))))
which could be shortened if C were more Lisp-like:

(and (bufferp object) (BVAR object name))

Lisp-like code from Emacs 18.59

DEFUN ("buffer-list", Fbuffer_list, Sbuffer_list, 0, 0, 0,
  "Return a list of all buffers.")
  return Fmapcar (Qcdr, Vbuffer_alist);

and the next function get_buffer after that:

... return Fcdr (Fassoc (name, Vbuffer_alist));

Done this way to be fast?
Show fundamental-mode from simple.el in Emacs 18.59

gud-def macro

gud uses a macro to translate its debugger command into a string sent to a real debugger.

For example, for gdb:

	      (gud-def gud-remove "clear %f:%l" "\C-d" "Remove breakpoint at current line")
expands to:

   (defalias gud-remove 
     (lambda (arg) '("Remove breakpoint at current line")
       (interactive "p")
       (if (not gud-running) (gud-call "clear %f:l" arg))))
   (local-set-key "\C-c\C-d" 'gud-remove)
   (global-set-key (vconcat gud-key-prefix "\C-d") 'gud-remove))

I suspect a macro isn't needed here.


This epitomizes a big problem with gud.el:

;; Where gud-display-frame should put the debugging arrow; a cons of
;; (filename . line-number).  Set by the marker-filter, which scans
;;; the debugger output for indications of the current program counter.
(defvar gud-last-frame nil)

;; Used by gud-refresh, which should cause gud-display-frame to redisplay
;; the last frame, even if it's been called before and gud-last-frame has
;; been set to nil.
(defvar gud-last-last-frame nil)

Problems with gud-last-frame

  • The name frame is weird.
  • No encapsulation: a bare cons node is used.
  • gud-last-last-frame suggests hackery.
  • Is a global variable.
    • Only one program can be debugged at a time

emacs-dbgr location

(defstruct dbgr-loc
"Our own location type. Even though a mark contains a
file-name (via a buffer) and a line number (via an offset), we
want to save the values that were seen/requested originally."
   num           ;; If there is a number such as a breakpoint or frame
                 ;; number associated with this location, this is set.
                 ;; nil otherwise.
   column-number ;; Column offset within line
   marker        ;; Position in source code
   cmd-marker    ;; Position in command process buffer

Elisp Structure Issues

  • Doesn't support Common Lisp :print hook
    • Add describe methods Show that
  • Access is clumsy

Elisp struct access

To access a field in dbgr-cmdbuf-info

(defstruct dbgr-cmdbuf-info
   bp-list ...
we write:

(dbgr-cmdbuf-info-bp-list dbgr-cmdbuf-info)

I have a macro to write instead:

(dbgr-sget 'cmdbuf-info 'bp-list)


  • Small functions
    • those that fit on a slide
  • Break out of the shackles of the environment...
    • when "tasteful"
    • Sometimes macros are useful here...
    • But don't overuse

Obligatory Image