cheerfulstoic
I feel like Elixir is getting big enough and old enough that I’m starting to experience problems with conflicting dependencies. An example from an application that I’m currently working with:
I went to try out the merquery library. This application uses version 1.0.2 of the jq library (the latest version, but from over five years ago) which in turn specifies poison ~> 4.0. The merquery library that I was adding specifies flint ~> 0.6 and flint 0.6.0, in turn, specifies poison ~> 6.0
This was actually just the beginning of the headaches and I had to chase down a few situations, making a couple of forks in the process to versions which didn’t conflict.
For a while I’ve been thinking that it’s wise practice to follow a general rule:
- When specifying dependencies for an application, prefer the
~>operator (either x.y or x.y.z generally) - When specifying dependencies for a library, prefer the
>=operator
I think pretty much everybody will agree with the first point. My thought on the second being: new versions of your dependencies will come along and, if there are bugs, you can fix your library (or if something is too difficult or you don’t have time you can add a ~> or <= constraint). But you shouldn’t stand in the way of applications wanting to use your library with newer versions of shared dependencies because probably most of the time they will work
Absolutely I think that you should consider your libraries use of each dependency. If you’re including jason and all you do is very simple usage of Jason.encode and Jason.decode, then the likelyhood that a major version will break things is low and you should probably use >=. If you’re using a library in a complex and intricate way, then you should consider if you should limit the versions you allow.
But I think that most people writing a library are used to using the ~> operator from building applications.
So my suggestions (given that this is the ideas/suggestions/proposals area of the forum):
- have some advice in the documentation
- if people are mostly in agreement, build a bot which goes to Elixir dependencies (especially more popular ones) and automatically suggests changes, along with a detailed explanation of the whys involved and things that the maintainer should consider on if they should or should not accept the change.
I’m happy to work on these things (and others) because I think it will be more and more of a big deal to help make Elixir development smoother in the long run (I’ve used npm enough to see how bad things can get
)
Also, this post from the Ruby world has some good discussion on the topic as well.
Trending in Proposals: Ideas
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
zachdaniel
You can override dependencies if necessary, but I think there is something major missing from overriding dependencies, specifically I think you ought to be able to say why you are overriding a dependency, and then mix can tell you when you don’t need to anymore.
For example:
says “I know that merquery wants a different version, but I’m overriding it”. Then if later you update
merquery, and no longer need the override, mix will instruct you to remove it. Additionally, if you add some new dependency that wants an older version ofjq, you have to acknowledge that you are also overriding that dependency.This makes it a bit safer to use
overrideas a consumer of libraries, which I think helps alleviate this issue a bit as well.cheerfulstoic
Yeah, good point… I didn’t know about the
overrideoption. Feels like!importantis CSSBut for making things smooth for Elixir devs, they would need to know about
override(I’ve been using Elixir for 6-7 years and I just learned about it!)I think in the case I outline that you’d need to add
poisonto your application’smix.exsand then force that into place maybe? Or could I forcejqand then it ignores its dependencies?I’m definitely not against the option of making
overrideclear in the documentation (with warnings, probably, and maybe in addition to my suggestions?)zachdaniel
Either one of those would work, yes
D4no0
Usually when I see this option being used in a codebase, it’s a red flag for me, as you can get into a situation where the dependency override might break that other library.
There are tools that allow library developers to define more flexible dependency versions, here is an example from ecto: ecto/mix.exs at master · elixir-ecto/ecto · GitHub
al2o3cr
FWIW,
>=in libraries can cause its own headaches, especially if the package being referenced doesn’t follow semver.For instance, here’s a pair of issues from
standardrbthat were ultimately driven by interactions between>=and already-locked versions:https://github.com/standardrb/standard/issues/340
https://github.com/standardrb/standard/issues/613
zachdaniel
I agree, but I think in some cases it is effectively unavoidable. I think we need to enhance it, not discourage its use. If I can say “I’m overriding to solve this specific dependency conflict that I’m aware of”, then most/all of the danger of using that option goes away.
D4no0
Well, this is the problem, you can’t really guarantee that unless you inspect the codebase of dependencies. The dynamic nature of elixir makes this even more dangerous, as it might blow in your face at runtime.
I think a potential solution would be to run unit tests of that library with the dependency you have at hand? If I’m not wrong this is what PERL does when you install packages, to make sure you don’t have dependencies mismatch somewhere. This OFC heavily depends on the library, as some libraries require a complex setup to run tests.
zachdaniel
I’m suggesting that this is built into the mix dependency resolver. Right now the following happens all the time:
footo my app. I already havebarandbaz.foodepends on a newer version ofbar.barbecausebazdepends on it.bazandfoousebar, and confirm that its fine to just override.{:bar, "~> ...", override: true}buzzto the app, which also depends on an old version ofbar.barfor the sake ofbuzzas well.fooreleases an update that depends on more stuff from the old version ofbar.foo, so we update it and have bugs.If instead of
override: true, I could say:which would say “this override only overrides the dependency that
fooat exactly versionx.x.xhas onbar”, then we are protected from any of those accidental changes.Adding
buzzwould produce an appropriate dependency conflict warning, solving Problem 1. We can then go look at the code/docs and decide if we want to override thebardependency for that version ofbuzzas well.foowon’t appear to be automatically upgradeable, solving Problem 2.D4no0
Great idea! It would certainly help a lot to get mismatch version errors, this is especially true for some of the bigger applications, where you might have 100+ dependencies.
I wonder if there is a language out there that solved this problem of “global” dependencies?
cheerfulstoic
Yeah, for sure… I guess that’s part of why I was trying to ephasize that one should prefer the use of
>=in a library, but I definitely wouldn’t say that you should always use it. I guess it feels like many people don’t think of it as an option, and so I worry about people not really thinking about it (and I get it, you’re trying to get your cool idea for a library out there in front of people)I think if we wanted to provide guidance to people, we should give people both options on dealing with such things depending on their usage of the dependency:
poison >= 4.0poison ~> 4.0 or ~> 5.0 or ~> 6.0/poison >= 4.0 and < 7.0But also perhaps some sort of tool that lets them know (as a library maintainer) when there is a new version of sub dependencies which aren’t being allowed (either as a part of
mixsomehow, or a bot that points in out in a pull request).For
override, I can see how either the documentation or the functionality could be improved as @zackdaniel outlined, though I’m not personally interested in tackling that problem.