Endless Parentheses

Ramblings on productivity and technical subjects.

profile for Malabarba on Stack Exchange

New on Elpa and in Emacs 25.1: let-alist

let-alist is the best thing to happen to associative lists since the invention of the cons cell. This little macro lets you easily access the contents of an alist, concisely and efficiently, without having to specify them preemptively. It comes built-in with 25.1, and is also available on GNU Elpa for older Emacsen.

If you've ever had to process the output of a web API, you've certainly had to deal with endless alists returned by json-read. I'll spare you the rant and go straight to the example.

Here's a very simplified version of a function of the SX package, before let-alist.

(defun sx-question-list--print-info (question-data)
  "DOC"
  (let ((tags               (cdr (assq 'tags               question-data)))
        (answer_count       (cdr (assq 'answer_count       question-data)))
        (title              (cdr (assq 'title              question-data)))
        (last_activity_date (cdr (assq 'last_activity_date question-data)))
        (score              (cdr (assq 'score              question-data)))
        (owner-name (cdr (assq 'display_name (cdr (assq 'owner question-data))))))
    (list
     question-data
     (vector
      (int-to-string score)
      (int-to-string answer_count)
      title "     "
      owner-name
      last_activity_date 
      sx-question-list-ago-string
      " " tags))))

And this is what the same function looks like now (again, simplified).

(defun sx-question-list--print-info (question-data)
  "DOC"
  (let-alist question-data
    (list
     question-data
     (vector
      (int-to-string .score)
      (int-to-string .answer_count)
      .title "     "
      .owner.display_name
      .last_activity_date sx-question-list-ago-string
      " " .tags))))

How much nicer is that? let-alist detects all those symbols that start with a ., and wraps the body in a let form essentially identical to the one above. The resulting code is much nicer to write, and the byte-compiled result is exactly as efficient as the manually written version. (If it's not byte-compiled, there will be a performance difference, though it should be small.)

And just to make things nicer, you can use this snippet to highlight those . symbols as if they were keywords.

(font-lock-add-keywords
 'emacs-lisp-mode
 '(("\\_<\\.\\(?:\\sw\\|\\s_\\)+\\_>" 0 
   font-lock-builtin-face)))

Update <2014-12-20 Sat>

Due to popular demand, let-alist now does nested alists. The example above shows how you can use .owner.display_name to access the value of display_name inside the value of owner.

Tags: package, emacs,

comments powered by Disqus