Why does Rust's Cargo not consider version 0.8.3 to have a compatible API with version 0.9.0? - rust

I'm reading the Rust book. Specifically this section about Semantic Versioning used by Cargo.
What doesn't really make sense is this:
The number 0.8.3 is actually shorthand for ^0.8.3, which means any
version that is at least 0.8.3 but below 0.9.0. Cargo considers these
versions to have public APIs compatible with version 0.8.3, and this
specification ensures you'll get the latest patch release that will
still compile with the code in this chapter. Any version 0.9.0 or
greater is not guaranteed to have the same API as what the following
examples use.
According to the rules for semantic versioning, a change of the minor version (from 0.8.3 to 0.9.0) can NOT contain changes that break the public API. Why does Cargo think that the public API for these 2 versions may not be compatible? Is it because the major version happens to be 0? If we were dealing with a case where the major version was > 0 (Ex. 1.8.3), would specifying 1.8.3 in Cargo.toml allow Cargo to install version 1.9.0 then?

As documented in the Specifying Dependencies chapter of The Cargo Book (emphasis added):
The string "0.1.12" is a semver version requirement. Since this string does not have any operators in it, it is interpreted the same way as if we had specified "^0.1.12", which is called a caret requirement.
Caret requirements
Caret requirements allow SemVer compatible updates to a specified version. An update is allowed if the new version number does not modify the left-most non-zero digit in the major, minor, patch grouping.
[...]
This compatibility convention is different from SemVer in the way it treats versions before 1.0.0. While SemVer says there is no compatibility before 1.0.0, Cargo considers 0.x.y to be compatible with 0.x.z, where y ≥ z and x > 0.

Related

What is the exact use of semver notation in package.json file?

I want to know the exact difference between the semver notations in package.json. Can someone explain me.
I think the npm documentation explains it well: https://docs.npmjs.com/cli/v6/using-npm/semver#advanced-range-syntax
Since there is a lot going on, perhaps a brief explanation of the two most common:
The caret modifier (^) will automatically go the highest minor and patch version, unless the major version is 0. In this case, will only update the patch version.
The tilde modifier (~) will only go to the highest patch version. So ~ and ^ are equal when the major version is 0.
Semver notation isn't specifically used in package.json.
If it's followed (*1), it helps developers to understand what to expect from any particular update. Imagine you want to bump the version of a library, and you see that the difference is in the major part of the version (n in n.*.*). This can point out to potential repercussions of upgrading the package - according to SEMVER MAJOR version when you make incompatible API changes,.
*1 It's not always followed by developers. One prominent example is React Native. The developers have never released a Major version, and treat MINOR as MAJOR
I got this from node js documentation. There is a pretty well explanation for question.
https://nodejs.dev/learn/the-package-lock-json-file
In package.json you can set which versions you want to upgrade to (patch or minor), using the semver notation, for example:
if you write ~0.13.0, you want to only update patch releases: 0.13.1
is ok, but 0.14.0 is not.
if you write ^0.13.0, you want to get
updates that do not change the leftmost non-zero number: 0.13.1,
0.13.2 and so on.
If you write ^1.13.0, you will get patch and minor releases: 1.13.1, 1.14.0 and so on up to 2.0.0 but not 2.0.0.
if you
write 0.13.0, that is the exact version that will be used, always

What does .post2 in pytorch versions means?

I was looking at torch versions
https://pypi.org/project/torch/#history
1.5.0
1.4.0
1.3.1
1.3.0.post2
1.3.0
1.2.0
1.1.0.post2
1.1.0
1.0.1.post2
1.0.1
1.0.0
0.4.1.post2
0.4.1
0.4.0
0.3.1
0.3.0.post4
0.1.2.post2
0.1.2.post1
And I found out that some versions have the suffix .post2 (or .post3, post4).
At first I thought it was a release made after the minor version X release already happened (postX), but then I saw 1.3.0.post2, so that doesn't seem to make sense.
Also, pytorch doesn't seem to follow semver.
What does postX mean?
It seems like related to PEP-0440 and post releases: https://www.python.org/dev/peps/pep-0440/#post-releases
Post-releases
Some projects use post-releases to address minor errors in a final release that do not affect the distributed software (for example, correcting an error in the release notes).
If used as part of a project's development cycle, these post-releases are indicated by including a post-release segment in the version identifier:
X.Y.postN # Post-release
A version identifier that includes a post-release segment without a developmental release segment is termed a "post-release".
The post-release segment consists of the string .post, followed by a non-negative integer value. Post-releases are ordered by their numerical component, immediately following the corresponding release, and ahead of any subsequent release.
Note
The use of post-releases to publish maintenance releases containing
actual bug fixes is strongly discouraged. In general, it is better to
use a longer release number and increment the final component for each
maintenance release.
But I still don't know how pytorch uses post since it seems to jump some postN versions .

Why does adding byteorder make Cargo downgrade mysql to version 8.0.0?

I've been developing a project in Rust for awhile. A few days ago I ran cargo update and a whole bunch of my dependencies got downgraded, and I haven't been able to figure out why. I created a new project and have found that if the dependencies in Cargo.toml are just
[dependencies]
mysql = "*"
it builds with the latest mysql (11.3.0) as I would expect. If I add
byteorder = "1"
then run cargo clean/cargo update, mysql gets downgraded to 8.0.0.
Any help figuring out why the byteorder dependency is making Cargo downgrade mysql or how to stop it from doing so would be appreciated.
how to stop it from doing so
This is the easy part: don't use wildcard versions. The chances of your code working with literally any version of that crate that has ever been published is, on average, zero.
why the byteorder dependency is making Cargo downgrade mysql
This is actually really hard to answer. Picking dependencies is an NP-hard problem. Since most programmers don't care to wait that long, there are heuristics and preferences and shortcuts in every dependency manager. I don't know all the nuances of Cargo's algorithm, so most of this is educated guesses or investigation.
You've told Cargo "I don't care what version mysql to use" by saying mysql = "*". Cargo is now free to use whatever version it wants to, a very flexible requirement.
In this case, mysql 11.3.0 has chosen to require byteorder = "~1.0". That does not allow byteorder 1.1.0. Some aspect of the dependency resolution sees this and says it'd be better to allow your crate to have version 1.1.0 of byteorder, even if that means that mysql needs to be downgraded to a non-conflicting version. The important thing is that version 8.0.0 was the last version that only requires byteorder 0.5.3.
If you try to force both to the current versions, you'll see this:
error: failed to select a version for `byteorder` (required by `mysql`):
all possible versions conflict with previously selected versions of `byteorder`
version 1.1.0 in use by byteorder v1.1.0
possible versions to select: 1.0.0
However, you can get almost fully updated:
[dependencies]
mysql = "11.3.0"
byteorder = "1.0.0"
I'm not fully sure why Cargo will allow you to have version 1.1 and 0.5 at the same time but not 1.1 and 1.0, but my guess is that a heuristic is to have only one semantic major version of a given crate.
Future enhancements to Cargo will likely introduce the concept of "public" and "private" dependencies, which will likely change the resolution algorithm as well as make this case better as byteorder is probably an internal dependency of mysql and you don't need to match it.

What is the breaking change in semver 2.0.0

There is a version 2.0.0 of the semantic versioning spec, given that you should:
increment the MAJOR version when you make incompatible API changes,
What was the incompatible change between semver 1.0.0 and 2.0.0?
I asked on the semver github repo. There are two changes that are not backwards compatible:
leading zeros are not accepted
minor version numbers MUST be incremented if API is marked as deprecated

Is 0.0.1 valid semver?

A colleague got into a casual argument about the first version of a module. We're wondering if 0.0.1 should be the initial release. I think 0.1.0 is the proper first version, as 0.0.1 implies an increment of a patch, and a patch implies a prior release. So from my understanding, there would have to be a 0.0.0.
I skimmed http://semver.org docs, which do say that 0.1.0 is usually the initial release, but I didn't see any rule against having a minor number set to 0 when the major version is also 0.
Does anyone know if 0.1.0 being the lowest possible version is a formal rule, or just a convention?
The semver 2.0.0 specification doesn't preclude it. The FAQ does recommend starting at 0.1.0 though.
How should I deal with revisions in the 0.y.z initial development phase?
The simplest thing to do is start your initial development release at 0.1.0 and then increment the minor version for each subsequent release.
There are no rules here and conventions are loose.
When the initial major number is zero, all that is guaranteed is that higher numbers come after lower ones. All the semantic versioning guarantees about "this is a bug fix" or "old functionality still works" only apply to version one or later.
While there is a loose convention of 0.1.0 being the lowest version number, there are those that would argue it the first version one shares with others. The specification of semantic versioning simply sees the leading zero and washes its hands.
As per the semver calculator (https://semver.npmjs.com/), it is not recognizing the versions which start with 0.0.x.Semver Calculator Screenshot
Semantic versoning (semver) is about 'safely moving your project forward.' — from the last line of the second para of the docs Introduction.
By this definition and purpose we SHOULD bump our version number for each release (bump version then commit).
From docs (Rule #2): The version numbers (MAJOR, MINOR, and PATCH are non-negative integers).
If you started at 0.0.0 you must bump to something likely 0.0.1 or 0.1.0 where the MAJOR '0' indicates you are still in development.You could very well bump straight to 1.0.0 where the MAJOR '1' indiciates an initial public release.
Remember the rules, if you bump MAJOR you must reset MINOR & PATCH to '0' ... If you bump MINOR, you must reset PATCH to '0'. This prevents you from bumping all three simoustaneously.
In order to release 0.0.0 you must start at 0.-1.-1 or 0.0.-1 in your package.json (YOU CANNOT BY RULE #2) such that when you release (bump version then commit) you have a release with semver number 0.-1.0 (YOU CANNOT BY RULE #2) or 0.0.0;
The FAQ for semver says "The simplest thing to do is start your initial development release at 0.1.0 and then increment the minor version for each subsequent release." They are speaking about the actual release; after you have done the (bump version then commit). This is mentioned because you could have a release numbered 0.0.1 which indicates you FIXED SOME BUGS.
0.0.0 = Initial Development Release (Does Not Exist)
0.0.1 = Bugs Fixed Since (0.0.0 | Where You Began)
0.1.0 = Features Added Since (0.0.0 | Where You Began)

Resources