Coder Social home page Coder Social logo

Comments (7)

Luis-Henriquez-Perez avatar Luis-Henriquez-Perez commented on August 20, 2024 2

I would consider your example an anti-pattern:

n in a :config section of the use-package declaration. That way, if some aspect of the foo package's declaration is changed (e.g. the user decides to defer loading it), such "free" forms needn't be tracked down and wrapped in eval-after-load

I see what you mean. I think my example was not specific enough. I'll use my own case as an example.

I use several external libraries (such as dash.el, anaphora, dbc, shut-up) to write my own macros and functions. The macros/functions I write are used pervasively throughout my init file. So pervasively that if I can't assume these libraries are installed I'd have to wrap what is honestly most of my init file in elpaca-use-package forms. At that point it would probably be better to opt for plan B--using a config.el file as you mention.

So if you configure a package once and don't use its function in other places--which to be fair is probably the case for most packages, then we're good. But if you have custom functions and macros that rely on several packages which are used throughout, this use-package nesting is not desirable/practical.

Then config.el can assume all packages are installed and activated.

Yes, as I was thinking about this I thought that creating another file with your actual config and loading that is the way to do it.

There is also the question of whether there is anything that needs to be done or a user is relying on being done before the after-init-hook--I imagine for most users there would be nothing, but it is something to keep in mind.

I would reconsider the idea of separating out the installation from the configuration, though.
IMO it will complicate your setup for no tangible benefit

The tangible benefit is that you can freely assume packages are installed (just as you would with built-in packages) as opposed to not being sure and needing to wrap any external package dependent code in an elpaca-use-package form.

such "free" forms needn't be tracked down and wrapped in eval-after-load

As you alluded to there are obvious benefits with use-package forms in the sense that if you decide to defer a package--or even remove it entirely--you can do it without breaking anything else. Packages are like puzzle-pieces that can be plugged in/removed in a robust fashion.

But there are also costs to coding this way--namely more boilerplate and a defensive coding style because you can't assume anything is installed yet.

from elpaca.

progfolio avatar progfolio commented on August 20, 2024

I think this point should be emphasized more in the readme. It is kind of mentioned in the FAQs, but I don't think it is stated directly enough.

There is an example in the https://github.com/progfolio/elpaca#installing-packages section. I've re-iterated it in the FAQ section.

elpaca provides integration with use-package for this, but still this means--at least from my understanding--that the user would likely have to wrap many "free" forms in elpaca-use-package blocks.

I would consider your example an anti-pattern:

(use-package foo :demand t)
;; can assume that foo is installed and initialized
(foo-message "hi")

In this example, the foo-message call should happen in a :config section of the use-package declaration. That way, if some aspect of the foo package's declaration is changed (e.g. the user decides to defer loading it), such "free" forms needn't be tracked down and wrapped in eval-after-load (duplicating what use-package's :config will expand to when the package loading is deferred).

Furthermore, I argue that the user should be able to "circumvent" this if they provide all their recipes via a lockfile. Something like elpaca-bootstrap-from-lockfile which would take a path to the lockfile.

It's not as simple as your example seems:

;; bootstrap-code
(...)
(elpaca-bootstrap-from-lockfile "~/.emacs.d/lockfile") ; processing done immediately since we already have all package recipes

;; can assume everything is setup and don't have to wait until after the `elpaca-after-init-hook`.
(require 'foo)
(foo-message "hi")

elpaca-bootstrap-from-lockfile would either have to block until all queues are processed (a non-goal of Elpaca) or take a callback which executes the forms below it. That would not be very flexible, because you would have to unwrap those forms if you changed your mind about loading the lockfile.

My current thoughts on the design of the lockfile system is to keep it simple.
Writing a lockfile will essentially create a menu. Each declared package will be associated with a full recipe.
Loading that lockfile will push that menu to elpaca-menu-functions, so its recipes will take precedence over other recipes. I've yet to implement lockfile reading, so this may change.

If I understand your desired use case correctly, a working setup would look something like this:

init.el:

;;bootstrap omitted
(add-hook 'elpaca-after-init-hook (lambda () (load-file "./config.el")))
(elpaca-load-lockfile "path/to/lockfile")

;; package declarations
(elpaca example-package)
;;etc

Then config.el can assume all packages are installed and activated.

I would reconsider the idea of separating out the installation from the configuration, though.
IMO it will complicate your setup for no tangible benefit (it will actually be slower, though it's impossible to say if that's a meaningful concern without measuring anything).

from elpaca.

progfolio avatar progfolio commented on August 20, 2024

There is also the question of whether there is anything that needs to be done or a user is relying on being done before the after-init-hook--I imagine for most users there would be nothing, but it is something to keep in mind.

Good point. I think cases which will not work by moving the execution to elpaca-after-init-hook will be rare. Noted, though.

But there are also costs to coding this way--namely more boilerplate and a defensive coding style because you can't assume anything is installed yet.

Always a tradeoff. IMO the boilerplate is greatly reduced by macros like use-package, so the benefit far outweighs the cost. Seems like the separate file solution should work for your use-case, though.

Thanks again.
Closing this issue, but feel free to open more if you have any other thoughts on how things can be improved.

from elpaca.

bestlem avatar bestlem commented on August 20, 2024

I think this is the issue I have.
I use use-package and have much of my init.el depending on package loaded. As I noted elsewhere I don't see the benefit of async loading as it just breaks things.

My elpaca init.el includes

(elpaca use-package (require 'use-package)) # as per examples 
# Then add a use-package keyword

# Keyword setup

# Then I need to alter the keyword list - which fails
(setq use-package-keywords
	  (cons :mwb-load-path use-package-keywords)
# use-package-keywords is undefined in elpaca but not in straight or package.el

from elpaca.

progfolio avatar progfolio commented on August 20, 2024

Try adding it just after your require in the elpaca body. If that doesn't work, please fill out the bug report form describing your issue.

from elpaca.

Dickby avatar Dickby commented on August 20, 2024

I'm dealing with similar problems, lot's of packages with functions that i use later on in my init file.
In my config file I define a lot of custom evil-operators and hydras, while it would be possible to wrap all of that inside the use-package block, but that wouldn't play nice with the way i order it in the org file i tangle from.
A possibility would be to start the file with the packages that are used later on, call elpaca-process-queues and add the stuff that depends on something.
Would there be a downside to this approach?

from elpaca.

progfolio avatar progfolio commented on August 20, 2024

@Dickby please open a separate support issue and include specific examples of what is giving you trouble. It's hard for me to give advice otherwise.

One piece of generic advice I can give regarding:

but that wouldn't play nice with the way i order it in the org file i tangle from.

If you are tangling, you have access to the noweb syntax, which should allow you to present your init file separately from the order in which it is tangled.

from elpaca.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.