0

If I'm using use-package in a file that I plan to byte-compile, can I still leverage Emacs' byte-compile-dynamic setting to lazy-load compiled function definitions? From the Elisp manual:

With dynamic function loading, loading the file doesn’t fully read the function definitions in the file. Instead, each function definition contains a place-holder which refers to the file. The first time each function is called, it reads the full definition from the file, to replace the place-holder.

So, for example, if my init.el loads a file,

(require 'my-persistence (concat user-emacs-directory "my-persistence")

in which I've put persistence-related settings,

(use-package savehist
  :commands savehist-mode
  :config
  (setq savehist-autosave-interval 60)
  (defun foo () ...)
  (defun bar () ...)
  (defun baz () ...))

(provide 'my-persistence)

I could add -*-byte-compile-dynamic: t;-*- to the top of that file, in hopes that lazy-loading the compiled function definitions of foo, bar, and baz reduces the time spent evaluating the :config section.

I imagine it playing out like:

  • my-persistence.elc is loaded
  • user calls savehist-mode
  • savehist package is loaded
  • :config section is evaluated
  • savehist-autosave-interval is set to 60
  • lazy-loading defers the full definitions of foo, bar, and baz
  • user calls foo
  • foo's full definition is loaded

I tried it out, and :config still behaves as expected, but I don't know how to check whether foo, bar and baz are in fact being lazy-loaded.

1

It looks like functions defined in the :config section will not participate in byte-compile-dynamic lazy-loading. I tested this by modifying the above example:

-*-byte-compile-dynamic: t;-*-

(defun foo () 5)

(use-package savehist
  :commands savehist-mode
  :config
  (defun bar () 5))

(provide 'my-persistence)

After savehist has been loaded, calling (symbol-function 'foo) returns:

#[nil
  ("/Users/ivan/.emacs.d/my-persistence.elc" . 473)
  nil 1]

Calling (symbol-function 'bar) returns:

#[nil "\300\207"
      [5]
      1]

Notice that foo currently holds a reference to the file where the full definition can be found, whereas bar holds the actual byte-compiled instructions and the 5 constant.

Indeed, after calling (foo), a subsequent (symbol-function 'foo) shows that the full definition has now been loaded:

#[nil "\300\207"
      [5]
      1]

What did work, however, was puting the function I want lazy-loaded into a separate file and requiring it from the :config section:

(use-package savehist
  :commands savehist-mode
  :config
  (require 'my-foo))

(provide 'my-persistence)

And in my-foo.elc

-*-byte-compile-dynamic: t;-*-

(defun bar () 5)

I don't know how practical that is, though I guess it might be depending how many functions you're defining (and how many you won't be needing right away). I also don't know how this approach stacks up against autoloads, but it was interesting to try, anyway.

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.