Endless Parentheses

Concise ramblings on Emacs productivity.

Support on Gratipay
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

Support on Gratipay
comments powered by Disqus