🌈 I provide private lessons on Emacs, Linux, and Life in general: https://protesilaos.com/coach/.

Re: Questions regarding use-package (Emacs)

The following is an excerpt from a recent exchange. It is reproduced with permission. The identity of my correspondent remains private.


I remember watching one of the earlier videos of yours where you mentioned you do not use use-package anymore. IIRC the reasoning was to utilise Emacs built-ins more and rely less on external code.

Just out of morbid curiosity, were there any other reasons? Since use-package is now part of the core, and you have matured even more as an Elisp developer, would you have any notes on improving use-package to make it more applicable for larger audience?

Another reason behind asking this is, I’ve been trying to get more into Elisp understanding and use-package, as it happens, was the project I picked to start with.

Any ideas/advice/suggestions welcome.

I will answer your question. Can I publish this on my website, so that I can reference it in the future if somebody else asks me? I want to include the quote directly above. I will keep your details a secret. Is that okay?

Starting with the point about prioritising built-in functionality: I continue to do so, though I also account for a package’s overall quality and fitness for purpose. If a third-party package appears to me as better than its built-in alternative, I opt for it. Examples include my modus-themes when I first designed them in response to my dissatisfaction with available built-in options, but also my preference for vertico over icomplete, ido, and even the standard Completions’ buffer.

This is informed by my refined understanding of what it means for a standalone package to be shipped with Emacs as opposed to being available in some package archive: there is no technical difference between the two. My modus-themes, for example, is a standalone package. It is the same whether a user gets it directly from core Emacs, some package archive, or clones it directly from the Git source. The inclusion of a standalone package in Emacs does not, in and of itself, somehow upgrade or alter it.

Exception to this are foundational packages that are meant to be used by other projects, such as for parsing data or creating new user interfaces (e.g. transient.el). Those benefit from inclusion in core Emacs, as they became a standard that the community can reference.

Couched in those terms, I think use-package does not change by its mere addition to core Emacs: it is not a foundational package that other projects need to depend on. So if I was not using it before, I have no reason to use it now. Which brings me to the “why” that is.

I stopped using use-package because (i) I did not like how its domain-specific language deviates from how the same things are done without it and (ii) did not want to deal with inconsistencies in its syntax.

The DSL is inconvenient for me. For example, the :custom entries cannot be evaluated on a per-form basis the way they are with, say, setq and now setopt. If I want to evaluate specific forms without the whole package declaration, I must take the forms out of their :custom context, rewrite them, and then do my work. Even if a keyboard macro or query-replace makes the rewrite easier, it still is something I have to do: it interferes with my flow. Same idea when converting the value of a :hook to the add-hook syntax; :map to define-key.

As for the inconsistencies I alluded to, I did not want to deal with how the :hook keyword defaults (or defaulted?) to omit “-hook” from hook symbols, while :map keeps the “-map” suffix in the corresponding symbols. I know that there is/was a user option for :hook, but that still breaks things for users who copy code that includes the suffix but have not set that option accordingly—I had to provide support for this incompatibility multiple times, to the point where I realised it was not worth it.

Taking a step back, the extra features of use-package such as :defer are not useful in my setup. I do not care about startup times. Not one bit. I launch Emacs once per session. When I am done, I close it and switch off the computer. The way I do it is to launch Emacs, go fetch a drink, and then get back where I expect everything to be available. So what if it takes 5 seconds or a minute? I was away from the computer. With :defer I would have to stop in the middle of my workflow to wait for the packages to become available. All for a small improvement to emacs-init-time that I was not benefiting from anyway, as I was still fetching my drink during startup.

I ended up using use-package as the equivalent of:

(progn
  ;; do stuff
  )

I know this is what use-package is reduced to once we remove all the extras (:custom, :hook, :map, :defer, …), so this is exactly what I did in my dotemacs. I did it my own way to prevent people from having the false safety of copy-pasting code without thinking about it. I want those who read my config to understand what they are doing. It works for me and is highly opinionated, which is what the Emacs spirit is all about.

I must stress that this is not an argument against use-package. I am happy that it is added to core, as it is the de facto standard. Lots of users will benefit from this change. It just so happens that I am not among them.