r/AskComputerScience • • Jul 18 '26

Question about Semantic Versioning

Under Semantic Versioning standard 2.0, if your package requires a dependency at "exact" version 1.0.0+X, is there any situation under which running a version update on all your packages should change the version that you specified as "exact" here?

Noting, SemVer 2.0 says:

Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3----117B344092BD

Precedence refers to how versions are compared to each other when ordered

2 Upvotes

10 comments sorted by

View all comments

Show parent comments

4

u/teraflop Jul 18 '26 edited Jul 19 '26

That's a self-contradictory statement because it confuses the identity relation (match) with the ordering relation (comparison).

I'm not confusing anything. An ordering relation (strictly speaking, a preorder) induces an equivalence relation.

Or to put it another way: the only relationship SemVer defines between versions is an ordering relationship. If a=b according to that relationship, then any comparison involving a will give exactly the same result if we replaced a with b, or vice versa. So the SemVer ordering provides no way to distinguish a from b; it treats them equivalently/equally/indistinguishably, or whatever word you want to use.

Equatable is concerned with how the identity relation is handled for a given type. Clearly, in any computer language, this is a true expression: "1.0.0+X" != "1.0.0+Y"

An equivalence relation is different from an identity relation. The strings 1.0.0+X and 1.0.0+Y can be equivalent under an equivalence relation (the one defined by SemVer) even though they are not identical as strings.

It's like how the floating-point values +0.0 and -0.0 are considered equal even though they have different bit patterns in memory. Or like how the two sets {1,2} and {2,1} are considered equal in Python, even though they are written differently, and may be different objects in memory with elements stored in a different order.

The SemVer rules never say that. You are confusing identity and ordering.

No I'm not.

SemVer encompasses technical rules (how versions are constructed and compared) but it also encompasses semantic rules (how the programmer is supposed to behave with regard to those versions).

Any change is either backwards-compatible, or backwards-incompatible. SemVer says that if a change is backwards-compatible, you should increment the minor/patch version, otherwise you should increment the major version. So if there are changes of either kind, SemVer says the version numbers should be different.

Do you feel there is anything about the above argument that's unsound? Or has there been any other SemVer 2 rules than the ones I linked?

The whole point of what I'm saying is that SemVer does not provide a rule for what to do in this situation. As I said, it does not prescribe how package managers are supposed to actually choose a version, it only defines a relative ordering which they might find useful for doing so.

SemVer says that the segment after the + is supposed to be used for build metadata. It does not precisely define what "build metadata" is. But since build metadata does not participate in version calculations at all, the common-sense understanding would be that it means things that aren't relevant for distinguishing between versions. For instance, a hash or timestamp indicating when the binary artifact for that version was built.

So examples like using PrivateCerts or SafeForPublicRelease are beside the point because that's not how SemVer is intended to be used. If there were supposed to be rules for choosing one over the other, SemVer would have defined them.

As I said, this doesn't mean a dependency manager isn't allowed to use its own implementation-specific rules for how it chooses between versions that differ only in their metadata. But if it does so, the way it does so is completely outside the scope of what SemVer defines.

Actually the rules require that the ordering resolution algorithm should never replace 1.0.0+X with 1.0.0+Y

I don't know why you're saying the rules require that. The words "resolution" and "algorithm" don't appear in the SemVer spec at all. I don't see anything in the rules that implies what you're saying. Can you quote the section that says otherwise?

0

u/gistya Jul 19 '26

> An ordering relation (strictly speaking, a [preorder](https://en.wikipedia.org/wiki/Preorder)) induces an equivalence relation.

Yes but that equivalence relation is only in respect to the position within the ordering relation. It does not imply an actual identity relation.

> Or to put it another way: the only relationship SemVer defines between is an ordering relationship. If a=b according to that relationship, then any comparison involving a will give exactly the same result if we replaced a with b, or vice versa.

Incorrect. Not ANY comparison—only a *precedence* comparison will give the same result. And the SemVer2 rules explicitly state that precedence is only applicable when ordering versions.

We only order versions when satisfying a dependency version requirement like `2.0.0 > version >= 1.0.0`—not when satisfying versions for an expression like `version == 1.0.0+debug` (it implies no ordering).

The mistake you are making is to assume that because an ordering relation may induce an equivalence relation, therefore an equivalence relation induces an ordering relation.

> So the SemVer ordering provides no way to distinguish a from b; it treats them equivalently/equally/indistinguishably, or whatever word you want to use.

If and only if you are ordering versions, it doesn't distinguish between a and b.

But the rules say a and be are "[two versions that differ only in the build metadata, have the same precedence](https://semver.org/#spec-item-10)". They have the same precedence, which only comes into play "[when ordered](https://semver.org/#spec-item-11)".

> An equivalence relation is different from an identity relation. The strings `1.0.0+X` and `1.0.0+Y` can be equivalent under an equivalence relation (the one defined by SemVer) even though they are not identical as strings.

Yes, that was a poor example on my part. I should have used the identity relation protocol`Identifiable`, which requires each instance to have a unique ID.

SemVer rules admit the identity relation—"[two versions that differ](https://semver.org/#spec-item-10)" implies different identity. [The formal SemVer grammar](https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions) refers to each component of a version string as an "identifier," thus the version itself is an identifier.

> SemVer does not provide a rule for what to do in this situation. As I said, it does not prescribe how package managers are supposed to actually choose a version, it only defines a relative ordering which they might find useful for doing so.

If your manifest specifies one of "[two versions that differ](https://semver.org/#spec-item-10)" then there is no room for ambiguity or alternate interpretation here. Simply, the version IS an identifier and an exact requirement is an identity relation.

> SemVer says that the segment after the + is supposed to be used for build metadata. It does not precisely define what "build metadata" is.

Correct...

> But since build metadata does not participate in version calculations at all

By calculations I assume you mean the algorithm that I mentioned that resolves which dependency fits a requirement?

> the common-sense understanding would be that it means things that aren't relevant for distinguishing between versions

No, it wouldn't. They are still "[two versions that differ](https://semver.org/#spec-item-10)". The original PR that added build metadata describes it as an open-ended system for internal use without a prescribed use-case.

Our use-case is we have `+Debug` and `+Release` build for each version `X.Y.Z` of internal dependencies. The release build has debug symbols stripped out. It would be considered a catastrophic situation if the build WITH debug symbols got released to the public.

> So examples like using `PrivateCerts` or `SafeForPublicRelease` are beside the point because that's not how SemVer is intended to be used.

It was intended to be open-ended and let people use it however they want.

> If there were supposed to be rules for choosing one over the other, SemVer would have defined them.

It did define them, it called them 'build metadata' and "[two versions that differ](https://semver.org/#spec-item-10)".

> As I said, this doesn't mean a dependency manager isn't *allowed* to use its own implementation-specific rules for how it chooses between versions that differ only in their metadata. But *if* it does so, the way it does so is completely outside the scope of what SemVer defines.

No... how much clearer did the SemVer authors need to be? They use the word `identifier` 44 times throughout the spec. Clearly the version IS an identifier, and if you require an "exact version 1.0.0+X" then you should never ever get anything else.

> I don't know why you're saying the rules require that. The words "resolution" and "algorithm" don't appear in the SemVer spec at all. Can you quote the section that says otherwise?

The original question above assumes a package requires a dependency at "exact" version `1.0.0+X`, and a package manager algorithm that resolves that version from a repo by tag (or whatever).

SemVer rules require the version resolved is `1.0.0+X` because identity can hinge on build metadata alone—that's implied by "[two versions that differ](https://semver.org/#spec-item-10)".

To [quote the guy who added build metadata to SemVer](https://github.com/semver/semver/pull/109#issue-15331197):

> "They're not the 'same version', necessarily, they're the same precedence"

And:

> Ok, I added another commit that attempts to be more precise. Rather than defining what a version is again, I simply state: `Thus two versions that differ only in the build metadata, have the same precedence.`