2

I'm new to Emacs and think I ran into some macro expansion problems. There's a function solarized-with-color-variables which is a macro that creates local variables using let* and then expands the macro body parameter inside the let* body so that it has access to these variables.

At one point I need to setq a variable to a value consisting of a list, the first element of which should take on the value of one of these variables, green. Normally I did this like this:

(setq some-var `(,green box))

However, it seems that after switching to using use-package.el's use-package macro, it seems like I'm in multiple layers of macros now, such that the above now expands one more time to:

(setq some-var (green box))

That is, it attempts to call green as a function, which it's not; it's a string.

I'm not sure how to go about fixing this, or how I should proceed. My guess is that I have to basically wrap it in another layer of quotes so that the extra expansion leaves it as is, but being new to Emacs Lisp I'm not really sure how to do this. I tried a couple variations of quote and list to no avail.

;; use-package is a macro
(use-package solarized-theme
  :ensure t
  :config
  (load-theme 'solarized-light t)

  ;; solarized-with-color-variables is a macro
  (solarized-with-color-variables 'light
    (custom-theme-set-faces
     'solarized-light
     `(show-paren-match ((,class (:foreground unspecified
                                  :background ,base02
                                  :weight normal)))))

    ;; I wanted to use with-eval-after-load but that's also a macro
    (eval-after-load 'evil
      (progn
        (setq some-var `(,green box))))))

Edit: I've come to realize that it is the eval-after-load function I'm using.

If I have this:

(solarized-with-color-variables 'light
    (setq evil-emacs-state-cursor `(,red box)))

Everything works. But if I put that inside of eval-after-load or vice versa, it breaks:

(eval-after-load 'evil
    (solarized-with-color-variables 'light
        (setq evil-emacs-state-cursor `(,red box))))

It says that the value of red, "#blah", is not a valid function. I imagine that it's expanding macros twice, once for solarized-with-color-variables so that it yields:

(setq evil-emacs-state-cursor '("#blah" box))

And then again (?):

(setq evil-emacs-state-cursor ("#blah" box))

Then when attempting to evaluate it it tries to use "#blah" as a function, which it's not. Using the code from my own answer actually is giving me problems too, I guess it's not exactly the same as the value I set manually which is '("#blah" box):

(setq some-var `(list ,green 'box))

1 Answer 1

5

What should work is to drop the eval-after-load:

(use-package solarized-theme
  :ensure t
  :config
  ...
  ;; solarized-with-color-variables is a macro
  (solarized-with-color-variables 'light
    ...
    (setq some-var `(,green box))))

It says that the value of red, "#blah", is not a valid function. I imagine that it's expanding macros twice, once for solarized-with-color-variables so that it yields:

It's calling green as a function but not because of nested macros, rather, it's because eval-after-load is a function, and functions have their arguments evaluated before they are called, so when you call

(eval-after-load 'evil
  (progn
    (setq some-var `(,green box))))

It firsts evaluates the progn which sets some-var to the list ("#859900" box) and returns that value (because setq returns the value it sets). The 2nd argument to eval-after-load is supposed to be a form to evaluate, so after evil is loaded it tries to evaluate ("#859900" box) as a form, i.e. call the first element as a function, which of course fails.

Usually you should quote the form you pass to eval-after-load, but in this case that would block green from being substituted, because would be gone when the evaluation happens. If you have set lexical-binding: t at the top of your init file, you can use lambda instead:

(eval-after-load 'evil
  (lambda ()
    (setq some-var `(,green box))))

This is the same as using with-eval-after-load:

(with-eval-after-load 'evil
  (setq some-var `(,green box)))

If you don't use lexical binding, you can sort of fake it by constructing the list to be evaluated:

(eval-after-load 'evil
  `(setq some-var '(,green box)))

But since you don't usually need to delay setqing variables, dropping the after-load stuff entirely is simplest for this particular case.

4
  • Thanks!! Indeed I realized a while ago that I don't need to do this for setqs, but I am still curious about all of this. Does the use of with-eval-after-load as you used it also require lexical-binding: t? I ask because I tried using it and it told me that the Symbol's value as variable is void, which seems to mean what you were saying, that it's gone by the time the evaluation happens. Is there some way to capture that value using something like a let binding, or something? Again I realize there's no need to do this, but I want to learn about elisp. Thanks again for the help so far. Jul 26, 2015 at 5:35
  • Nevermind, I don't think that would be possible. It seems like all solutions depend on lexical-binding: t. So does the use of with-eval-after-load in this scenario, is that correct? Jul 26, 2015 at 5:41
  • Lexical binding is what allows the lambda to capture the binding for green. You can look at the definition for with-eval-after-load to see that it's just a macro that adds the lambda for you. I added a possible solution that works without lexical binding, it's not quite as nice though.
    – npostavs
    Jul 26, 2015 at 7:51
  • Yeah I know I don't need to do this for setq, it was just to learn about elisp. Thanks a ton! Jul 26, 2015 at 7:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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