jwiegley / use-package

A use-package declaration for simplifying your .emacs
https://jwiegley.github.io/use-package
GNU General Public License v3.0
4.39k stars 259 forks source link

Q: why can't I use a function in `:config` above its definition point? #882

Closed aspiwack closed 3 years ago

aspiwack commented 3 years ago

I'm genuinely curious about this one.

Normally, I can define functions in any order, like in this convoluted mutually-recursive parity check:

(defun ping (n)
  (if (<= n 0) 0 (pong (- n 1))))

(defun pong (n)
  (if (<= n 0) 1 (ping (- n 1))))

But it seems that I can't use a function in the :config block of a package if the definition is below. E.g.

(use-package a-package
  :config
  (helper-function))

(defun helper-function () …)

This will fail with “void function definition” or such.

It's really not clear to me why this is happening. (it also hurts the tidiness of my Emacs config a little, so if there is a workaround, let me know :slightly_smiling_face: )

aspiwack commented 3 years ago

I'm not really sure what the conditions are for this behaviour to happen.

In this case, I was loading an org file with org-babel-load-file inside my init.el. And since I don't seem to be passing an argument to org-babel-load-file, I assume it's not being byte compiled.


I did find a workaround for this particular use-case: using Org Babel's noweb syntax to reorder the files on load.

conao3 commented 3 years ago

use-package is not magic, it is just a macro. That generated Sexp could check using macroexpand.

(setq use-package-expand-minimally t)
;;=> t

(macroexpand-1
 '(use-package a-package
    :config
    (helper-function)))
;;=> (progn
;;     (require 'a-package nil nil)
;;     (helper-function)
;;     t)

so, you must define helper-function before use-package. As a simple, define in :config block, it should work well.

(macroexpand-1
 '(use-package a-package
    :config
    (defun helper-function ()
      (message "some awesome function."))

    (helper-function)))
;;=> (progn
;;     (require 'a-package nil nil)
;;     (defun helper-function nil (message "some awesome function."))
;;     (helper-function)
;;     t)
aspiwack commented 3 years ago

I think I got it. The answer is because use-package doesn't define a symbol, therefore the evaluation is not delayed. Makes sense, thanks.