2

This requires the let-alist package available on the GNU ELPA (built-in in 25.1).

I have the following macro:

(defmacro sx-assoc-let (alist &rest body)
  (declare (indent 1) (debug t))
  (require 'let-alist)
  `(progn
     (sx--ensure-site ,alist)
     ,(macroexpand
       `(let-alist ,alist ,@body))))

For some reason, the two forms don't evaluate as equal, but when I evaluate them separately they do indeed 'show' the same thing.

(equal `(progn (sx--ensure-site data)
         ,(macroexpand
           '(let-alist data .test)))
        (macroexpand
         '(sx-assoc-let data .test)))

What is going on here?

3

It's not a bug, it's a feature.

Why it happens

let-alist takes its first argument (the alist) and stores it in an uninterned symbol (generated by make-symbol). This is just a standard practice of macros to avoid evaluating arguments multiple times, because they need to be referenced multiple times.

The side-effect of this is that no two expansions of let-alist will ever be equal (because each one contains a unique symbol), so your test fails.

How to avoid this

The way to fix this (which I use when testing let-alist specifically) is to override make-symbol in the tests:

(cl-letf (((symbol-function 'make-symbol) (lambda (x) 'alist-symbol)))
  (should ...))

This should ensure make-symbol always returns the same thing.

However:

This is really a testament that you should test behavior, not implementation. It doesn't matter what sx-assoc-let expands to, as long as it returns the right values. You may want to get rid of that test entirely, in place of tests that just verify the return value of .variables.

| improve this answer | |
  • I did see that in the changelog :) Testing the behavior rather than the form itself is actually exactly what I ended up doing. – Sean Allred Dec 31 '14 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.