Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add caret requirements (^x.y.z) support to Version module #11448

Closed
wants to merge 1 commit into from

Conversation

simnalamburt
Copy link

@simnalamburt simnalamburt commented Dec 5, 2021

Implemented caret requirements support, and added unit tests regarding carot requirements feature.

Caret requirements (^x.y.z) are supported many languages like Rust Cargo, PHP composer, python poetry, and Node.js NPM. It has the advantage of being able to designate semver compatible version specifications in more detail conveniently. There is no harm in supporting it, so I hereby added the implementation.

CC @guersam

Co-authored-by: Jisoo Park jisoo.park@doomoolmori.com

Fun fact: I've wanted this feature since 2017-04-09.

References:

- Implemented caret requirements support
- Add unit tests regarding carot requirements feature

Caret requirements (^x.y.z) are supported many languages like Rust and
Node.js. It has the advantage of being able to designate semver
compatible version specifications in more detail conveniently. There is
no harm in supporting it, so I hereby added the implementation.

References:
  https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements
  https://docs.npmjs.com/cli/v6/using-npm/semver#caret-ranges-123-025-004
  npm/npm#4587

CC @guersam

Co-authored-by: Jisoo Park <jisoo.park@doomoolmori.com>
@josevalim
Copy link
Member

Hi @simnalamburt, thank you for the PR!

You can achieve similar behaviour by doing this: ~> 2.4. The difference between ^ and ~>, however, comes when using all three parts of the version. ~> 2.4.1 is not the same as ^2.4.1, as the first will not accept 2.5.0 but the second will.

However, I prefer the Elixir behaviour here: if you need to specify a specific patch version of a package, then you should explicitly opt-in into depending on all of its minor versions too.

Therefore, we need to answer if this difference is enough to introduce a new construct? Because, while there is no harm per se, it is a new construct that developers need to learn and understand when learning the language. Plus new code to maintain that will impact Elixir and likely all of Hex.pm users.

For those reasons, I don't believe we should go ahead with this. There is a cost in API surface and I am not sure the extra properties it brings are desired either.

In any case, thanks once again for the PR! ❤️

@josevalim josevalim closed this Dec 5, 2021
@simnalamburt
Copy link
Author

simnalamburt commented Dec 5, 2021

I think many Elixir packages use semantic version management customarily. This feature will prevent many libraries from being unnecessarily tied to past versions and will be very convenient for semver users.

And since It is already a function supported by many package managers, so I don't think the learning cost will be too high.

It is true that code maintenance costs would be increased, but please also note that version.ex module is a module that are not very frequently updated. 😢

@josevalim
Copy link
Member

Can you please start a discussion in the Elixir mailing list then? We should get some more visibility into the discussion. :) Having both ~> and ^ will definitely be a point of confusion, even if ^ already exists elsewhere.

@simnalamburt
Copy link
Author

That would be better. Thanks!

@ericmj
Copy link
Member

ericmj commented Dec 5, 2021

^ doesn't add anything that ~> doesn't do today. But having two operators that do similar things will lead to confusion for users, for example in error messages where a ^1.2.0 requirement could be translated to ~> 1.2 and vice versa.

@simnalamburt
Copy link
Author

simnalamburt commented Dec 5, 2021

Actually ^ does do something that ~> cannot do like >=1.2.3 and <2.0.0 which is pretty what we need if we're using SemVer.

I don't think there will be much confusion from my experience in other languages (almost all users prefered ^ over ~> if ^ is supported), but let's talk about it on the mailing list anyway. (I didn't create a thread yet)

@ericmj
Copy link
Member

ericmj commented Dec 5, 2021

Actually ^ does do something that ~> cannot do like >=1.2.3 and <2.0.0 which is pretty what we need if we're using SemVer.

That is what ~> does. Please check the documentation for that operator: https://hexdocs.pm/elixir/Version.html#module-requirements.

@josevalim
Copy link
Member

@ericmj there is a very tiny difference. ^1.2.3 is the same as ~> 1.2.3 or ~> 1.3.

@ericmj
Copy link
Member

ericmj commented Dec 5, 2021

Right, I disagree with the point that that specific functionality is needed for SemVer.

It is unlikely we would be adding support for ^ to Hex because it would be confusing for users when there are two overlapping operators that we have to pick from when displaying error messages to users.

When we resolve versions in Hex we convert ~> 1.2 to >= 1.2.0 and < 2.0.0-0 since the algorithm is working with version ranges, when resolution fails we need to explain to users why, so we would say something like: "couldn't select postgrex 2.0.0 because ecto requires postgrex ~> 1.2". But if ^ existed we could just as well say "postgrex ^1.2.0" even though ecto's dependency definition is "postgrex ~> 1.2" which would be confusing to users.

Error messages are just one reason why it would be confusing, having multiple ways of doing the same thing is confusing in general and means that developers has to learn both operators and make a conscious choice between when to use which.

Since I think this feature request is specifically for Hex (please correct me if I am wrong @simnalamburt) I don't think we should go ahead with adding it to Elixir when it won't be added to Hex.

@simnalamburt
Copy link
Author

OK I won't push this PR further, since eric said this feature won't be added to Hex. I'm leaving this note just for the records:

Many existing elixir users are already confused by odd behavior of ~>. Just like @ericmj confused ~> 1.2.3 with >= 1.2.3 and <2.0.0, many elixir users misunderstoods the behavior of ~>.

hackney: (~80000k downloads)
image

nebulex_redis_adapter: (~100k downloads)
image

Due to this, many packages' dependencies are unnecessarily tied to past versions.

To prevent this, many users are using two ~>s just like @josevalim demonstrated.

plug: (~70000k downloads)
image

These problems can be solved with ^ support. These problems already occured in other languages too and these are why Rust, PHP, Python, Node have ^ support.

@ericmj
Copy link
Member

ericmj commented Dec 5, 2021

The examples you listed are not examples of where the package author is confused about how ~> works (and neither am I 😄). They have explicitly chosen to only depend on the minor version of the packages which proves that there is a use case for the current behavior of ~> x.y.z.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants