mirror of
https://github.com/semver/semver.git
synced 2026-07-11 05:12:48 -05:00
What should the size of numeric identifiers be? #218
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @zafarkhaja on GitHub (Apr 28, 2016).
In my Java implementation of the specification (
jsemver) I use Java'sint(32-bit) type for the numeric identifiers. The users of the library often use it to parse versions and ranges generated and used bynode-semver. So occasionally I get feature requests from people asking me to increase compatibility betweenjsemverandnode-semverand I don't mind most of the times. But recently I received a pull-request (zafarkhaja/jsemver#28) with a change that uses Java'slong(64-bit) type for numeric values. Turns out that some people from thenode-semvercommunity useNumber.MAX_SAFE_INTEGER(9,007,199,254,740,991) for the version numbers (biggest-version-number). It's not something very common but still...So my concern is that it's not portable across languages but the spec should be language agnostic. Even if I use
longfor this who can guarantee there won't be any bigger number than whatlongcan represent (Number.MAX_VALUE)?There was a similar discussion here (#79) about the version string's length which resulted in a new FAQ entry saying something along this line "255 characters is overkill, use good judgment". While using
Number.MAX_SAFE_INTEGERdoesn't make versions longer than 255 characters I don't think it's good judgment either. I kind of understand why people might want to have a sort ofVersion.MAX_VALUEbut I believe we can achieve the same result with a 32-bit number, or even with a smaller one, it's just that 32-bit integers are pretty common across all languages, I suppose. In my opinion9,007,199,254,740,991is too much of an overkill compared to 255 characters.Any thoughts would be much appreciated.
@nikin commented on GitHub (May 20, 2016):
Let's asume that there is someone who releases a new version every hour to their software for 100 years. That comes down to 876 000 (will be less because of leap years) versions. Which is fine in 32bits. Let's make that every minute, 52 560 000.. still fine in 32bit integers. Let's go for every second: 3 153 600 000, and this is where it will only fit in an unsigned 32bit integer.
Now. we can establish that all these changes have to be in the same part of the version number, as any change higher will reset the lower numbers to 0.
Let's see the 3 options:
Major release every second (this will make updates impossible.), The specification declare's that an API must be defined for every major version. I do not see this a real case. Breaking APIs every second.
Also the recomended deprecation notices would double up the number of releases to 2 every second.
Minor release every second is something for an expansion of an API every second. This would be illogical, The API should go up one level, and make the code handle the additions without breaking the API. Even if this is a real case. It means at least a new line every second. making the release every second a tough job with a close to 200 MB source(the bare minimum).
Patch version every second is easily fixed by just bumping the minor version every day or so. The stuff mentioned for the Minor versions still applies.
So 64bit is overdoing it.. waaay overdoing it.
@haacked commented on GitHub (May 23, 2016):
Who has a CI/build system fast enough to do a build every second? Where can I get that? 😉
@nikin good answer! I'll consider this closed now.
@zafarkhaja commented on GitHub (May 24, 2016):
Guys, I'm glad we all agree on this but the issue hasn't been resolved yet. There are still implementations that are incompatible; a version generated by one implementation in one language can't be correctly parsed by another implementation in another language. I think it's a specification problem, thus the issue has to be addressed in the specification, right?
@nikin commented on GitHub (May 24, 2016):
To some extent i agree. but binary representations of semver are a bad idea in my opinion. Some systems do not handle 64bit integers. Some do not have unsigned ints. Some do not have ints at all.
A Full implementation of semver will need to use strings to implement paragraph 11.
So a 100% accurate implementation at the moment would use BIGINT, while parsing. Or parse the string directly.
Paragraph 2 could be rewritten to be more clear on that.
Maybe something like:
A normal version number is a string, which MUST take the form "X.Y.Z" where X, Y, and Z are dot-separated, non-negative base ten integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: 1.9.0 -> 1.10.0 -> 1.11.0.
@orent commented on GitHub (Apr 19, 2017):
Even if 9,007,199,254,740,991 is unanimously agreed to be a perverse - what about 20171231235959 ?
Still >32 bits
@ghost commented on GitHub (Jul 6, 2017):
I do think there is value in specifying a maximum for these fields.
Personally I'd be happy if the major/minor/patch fields were limited to 32 bit signed (so effectively 31 bits). This allows 20171231 for fields, which I think I've seen in real-world version numbers. It doesn't allow 20171231235959, but that doesn't bother me at all :) and I doubt very many people really use values that exceed 2^31.
It also makes sense to constrain the maximum value of any digit-only fields in the pre-release part of the version number, because the specification says these should be compared numerically.
I'd personally also like it if semver constrained the total length of the version string to be 255 or fewer characters.
@hofmand commented on GitHub (Jul 7, 2017):
Choosing a certain maximum number of bits violates the Zero-One-Infinity Rule, so I'm with Nikin on setting no limits and keeping everything as strings. Besides, it saves a step when you don't have to convert the strings to integers before comparing them.
@orent commented on GitHub (Jul 7, 2017):
No, it does not save a step because you must do something to ensure numbers are compared by numeric value rather than lexicographically. Converting the components to binary numbers, padding them with fixed number of leading zeros/spaces or comparing the number of digits before comparing as strings are all valid implementation approaches.
I would suggest a limit specified as a number of decimal digits, but in consideration of implementations based on internal representation as binary numbers. So either 9 or 15 digits limit (for 32 and 53 bits, respectively).
Sure, it would be nice if people kept the numbers short. But is there a strong argument why timestamps should be disallowed by the spec? They are used quite frequently in version numbers "out in the wild". So I would favor 15 digits.
BTW, I've just received an IERS update that the example timestamp I used (20171231235959) will not be followed by a leap second...
@hofmand commented on GitHub (Jul 7, 2017):
Use one loop to compare the two strings digit by digit. If one string ends first, the other number is numerically larger. This is simple and efficient for non-negative integers without leading zeros.
@markusschaber commented on GitHub (Sep 5, 2018):
Or compare the length first - as leading zeroes are not allowed, the longer string is automatically the numerically bigger one.