[GH-ISSUE #89] The concepts of equality, precedence and dependency satisfaction #7039

Closed
opened 2026-06-20 16:39:31 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @tbull on GitHub (Apr 18, 2013).
Original GitHub issue: https://github.com/semver/semver/issues/89

This appears to be a Java specific question that hit me in the course of implementation. But maybe it's not. Maybe it's a question for underlying concepts.

How should build information be compared? The spec says, it should not be accounted for in a precedence decision. But should it also not be considered when testing for equality? For example, are X.Y.Z+build.1 and X.Y.Z+build.2 equal?

This question might be a little Java specific. Java has the concept, that "the natural ordering for a class C" may or may not "be consistent with equals". This concept is described in the Comparable interface, which a class must implement to define a natural ordering on itself. In Java, all objects also have an equals() method, which determines, if two objects are "equal". The question here is if the equals() method's notion of equality and the compareTo() method's notion are the same.

I'm inclined to think that two SemVer objects representing the SemVer strings X.Y.Z+build.1 and X.Y.Z+build.2 are not equal, so equals() should return false. However, if the build metadata does not influence the ordering, compareTo() would return 0 in this case, which means for matters of the natural order the two objects are equal. This means, the natural ordering for this SemVer class is not consistent with equals.

While this is probably not the end of the world, this has some unfortunate consequences in certain usage scenarios. SemVer objects might be used as keys in a SortedMap, for example in some kind of dependency server. Such a map would violate Java's general Map contract, if the ordering in use is not consistent with equals. To remedy this situation, a separate Comparator has to be provided, which takes build information into account to be consistent with equals.

Maybe the actual problem here is a confusion of concepts. With the concepts being

  1. equality
  2. ordering (or precedence in SemVer parlance)
  3. dependency satisfaction.

Any thoughts?

Originally created by @tbull on GitHub (Apr 18, 2013). Original GitHub issue: https://github.com/semver/semver/issues/89 This appears to be a Java specific question that hit me in the course of implementation. But maybe it's not. Maybe it's a question for underlying concepts. How should build information be compared? The spec says, it should not be accounted for in a precedence decision. But should it also not be considered when testing for equality? For example, are X.Y.Z+build.1 and X.Y.Z+build.2 equal? This question might be a little Java specific. Java has the concept, that "the natural ordering for a class C" may or may not "be consistent with equals". This concept is described in the [`Comparable` interface](http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html), which a class must implement to define a natural ordering on itself. In Java, all objects also have an `equals()` method, which determines, if two objects are "equal". The question here is if the `equals()` method's notion of equality and the `compareTo()` method's notion are the same. I'm inclined to think that two SemVer objects representing the SemVer strings X.Y.Z+build.1 and X.Y.Z+build.2 are **not** equal, so `equals()` should return `false`. However, if the build metadata does not influence the ordering, `compareTo()` would return 0 in this case, which means for matters of the natural order the two objects are _equal_. This means, the natural ordering for this SemVer class is **not consistent** with equals. While this is probably not the end of the world, this has some unfortunate consequences in certain usage scenarios. SemVer objects might be used as keys in a [`SortedMap`](http://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html), for example in some kind of dependency server. Such a map would violate Java's general `Map` contract, if the ordering in use is not consistent with equals. To remedy this situation, a separate [`Comparator`](http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html) has to be provided, which takes build information into account to be consistent with equals. Maybe the actual problem here is a confusion of concepts. With the concepts being 1. equality 2. ordering (or precedence in SemVer parlance) 3. dependency satisfaction. Any thoughts?
Author
Owner

@jeffhandley commented on GitHub (Apr 30, 2013):

It will be up to the implementer to decide how to sort builds. I expect many will go with alphanumeric, but it's important for the spec to indicate that precedence cannot be discerned from the build metadata.

Consider 2 build servers running in parallel; build servers A and B. A may start before B even though B finishes before A. If they each stamp the version with build metadata, which should get precedence? It's non deterministic.

I don't think your question is Java specific though, as any implementation will have to make the choice of how to handle Equals and CompareTo.

I propose:

  1. Equals should return false whenever the build metadata differs
  2. CompareTo could return the value of the alphanumeric comparison of the build metadata (assuming the rest of the version number is identical).

Do you think the spec itself needs to be augmented to reflect this discussion, or can we keep the spec as-is and perhaps create an "Implementation Addendum" as a separate document?

<!-- gh-comment-id:17219444 --> @jeffhandley commented on GitHub (Apr 30, 2013): It will be up to the implementer to decide how to sort builds. I expect many will go with alphanumeric, but it's important for the spec to indicate that precedence cannot be discerned from the build metadata. Consider 2 build servers running in parallel; build servers A and B. A may start before B even though B finishes before A. If they each stamp the version with build metadata, which should get precedence? It's non deterministic. I don't think your question is Java specific though, as any implementation will have to make the choice of how to handle Equals and CompareTo. I propose: 1. Equals should return false whenever the build metadata differs 2. CompareTo could return the value of the alphanumeric comparison of the build metadata (assuming the rest of the version number is identical). Do you think the spec itself needs to be augmented to reflect this discussion, or can we keep the spec as-is and perhaps create an "Implementation Addendum" as a separate document?
Author
Owner

@Tieske commented on GitHub (Apr 30, 2013):

equals has two implementations;

  1. actually being the same build (compares on build meta data)
  2. being the same version (ignores build meta data)
<!-- gh-comment-id:17256728 --> @Tieske commented on GitHub (Apr 30, 2013): `equals` has two implementations; 1. actually being the same build (compares on build meta data) 2. being the same version (ignores build meta data)
Author
Owner

@TimLovellSmith commented on GitHub (May 3, 2013):

Hm. I felt confused about why Equals returns false even if the build metadata is identical?
I think a possible source of confusion here is that there can be many different application specific notions of 'equivalence'. Substitutability for satisfying a dependency is one notion. Being the same exact version identifier for purposes of e.g. cache lookup is another, different notion. And Equals(), CompareTo(), and GetHashCode() are all intended to satisfy the second purpose, not the first.
So Equals(), CompareTo(), and GetHashCode() should all treat build number as significant, and we should impose an arbitrary but consistant order for purposes of CompareTo(). I propose the logical arbitrary order should be same as using string comparison (non-culture-specific, ignore case?), since the 'type' of build identifier is effectively specified as string.

<!-- gh-comment-id:17421273 --> @TimLovellSmith commented on GitHub (May 3, 2013): Hm. I felt confused about why Equals returns false even if the build metadata is identical? I think a possible source of confusion here is that there can be many different application specific notions of 'equivalence'. Substitutability for satisfying a dependency is one notion. Being the same exact version identifier for purposes of e.g. cache lookup is another, different notion. And Equals(), CompareTo(), and GetHashCode() are all intended to satisfy the second purpose, not the first. So Equals(), CompareTo(), and GetHashCode() should all treat build number as significant, and we should impose an arbitrary but consistant order for purposes of CompareTo(). I propose the logical arbitrary order should be same as using string comparison (non-culture-specific, ignore case?), since the 'type' of build identifier is effectively specified as string.
Author
Owner

@Tieske commented on GitHub (May 3, 2013):

So Equals(), CompareTo(), and GetHashCode() should all treat build number as significant, and we should impose an arbitrary but consistant order for purposes of CompareTo().

I don't think so. Build metadata is excluded from any precedence calculations. So it should not be used in the comparison. Imo equals() returns version compatibility and does not take buildmetadata into account. You could add equalbuilds() to specifically check for that.

<!-- gh-comment-id:17421963 --> @Tieske commented on GitHub (May 3, 2013): > So Equals(), CompareTo(), and GetHashCode() should all treat build number as significant, and we should impose an arbitrary but consistant order for purposes of CompareTo(). I don't think so. Build metadata is excluded from any precedence calculations. So it should not be used in the comparison. Imo `equals()` returns version compatibility and does not take buildmetadata into account. You could add `equalbuilds()` to specifically check for that.
Author
Owner

@Tieske commented on GitHub (May 3, 2013):

additionally equals() should probably take an optional boolean argument indicating whether pre-release version are allowed, where the default value is false.

<!-- gh-comment-id:17422030 --> @Tieske commented on GitHub (May 3, 2013): additionally `equals()` should probably take an optional boolean argument indicating whether pre-release version are allowed, where the default value is `false`.
Author
Owner

@haacked commented on GitHub (May 6, 2013):

Coming in late here to reiterate what others have already said. Whether the build metadata should come into account when comparing two versions for equality depends on the context.

In any case, I don't think there's anything actionable here for SemVer itself.

<!-- gh-comment-id:17508813 --> @haacked commented on GitHub (May 6, 2013): Coming in late here to reiterate what others have already said. Whether the build metadata should come into account when comparing two versions for equality depends on the context. In any case, I don't think there's anything actionable here for SemVer itself.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/semver#7039