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?

Sean Allred
  • 6,861
  • 16
  • 85
  • I don't have let-alist.el, but did you mean `. test` instead of `.test`? – Drew Dec 31 '14 at 01:46
  • @Drew No, I do not :) It is a special marker syntax introduced by `let-alist`; see [this blog post](http://endlessparentheses.com/new-on-elpa-and-in-emacs-25-1-let-alist.html) and, of course, [the ELPA page](https://elpa.gnu.org/packages/let-alist.html). In short, `(let ((.test (cdr (assoc 'test data)))) ...)`. – Sean Allred Dec 31 '14 at 01:59
  • After learning a bit more of ERT, I've discovered that the fundamental cause is a [`different-symbols-with-the-same-name` error](https://github.com/vermiculus/sx.el/issues/151#issuecomment-68419695). I'm not entirely convinced there is a way to truly fix this. Related: [ERT, equality test fails due to different symbols which must be considered same](http://stackoverflow.com/q/13570005/1443496) – Sean Allred Dec 31 '14 at 02:55
  • Yes, interesting. I think you answered your question. ;-) – Drew Dec 31 '14 at 05:43
  • Oh, I see you figured that out. https://code.google.com/p/i-iterate/source/browse/trunk/tests/i-test.el#44 once I had a similar problem too, this is how I've solved it. – wvxvw Dec 31 '14 at 06:50

1 Answers1

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.

Malabarba
  • 22,878
  • 6
  • 78
  • 163
  • 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