sure it looks weird if you omit the patch part of semver. However, if you think that 2 > 12, perhaps, you're not the target audience for versions in general. /s
I've seen bugs caused by a tool not knowing that version `1.12` < `1.20` :/ so yeah, some professional developers don't know that.
Windows 95 reported it's version as 3.95 instead of 4.00 for this exact reason [0]. Apparently, writing lexicographical ordering on tuples is surprisingly unintuitive:
bool operator<=(version lhs, version rhs) {
return (lhs.Major <= rhs.Major) || (lhs.Minor <= rhs.Minor) || (lhs.Patch <= rhs.Patch);
}
looks correct for anyone who have never wrote such comparison before, but of course it's wrong. The correct one is bool operator<=(version lhs, version rhs) {
return (lhs.Major < rhs.Major)
|| ((lhs.Major == rhs.Major) && ((lhs.Minor < rhs.Minor)
|| ((lhs.Minor == rhs.Minor) && (lhs.Patch <= rhs.Patch))));
}
[0] https://devblogs.microsoft.com/oldnewthing/20040213-00/?p=40...
Re:Sentimental Versioning
by Lvl999Noob on Monday October 12, 2020 @10:11AM
(#24754483)
Your second code is wrong. For lhs = "4.3.7" and rhs = "3.3.7", your code will give true. It should be false.
Uh, no it won't?
cat >test_ver.cpp << EOF
#include <cstdio>
struct version {
int Major;
int Minor;
int Patch;
version(int major, int minor, int patch)
: Major(major)
, Minor(minor)
, Patch(patch)
{ }
};
bool operator<=(version lhs, version rhs) {
return (lhs.Major < rhs.Major)
|| ((lhs.Major == rhs.Major) && ((lhs.Minor < rhs.Minor)
|| ((lhs.Minor == rhs.Minor) && (lhs.Patch <= rhs.Patch))));
}
int main(int argc, char **argv) {
version lhs(4, 3, 7);
version rhs(3, 3, 7);
printf("lhs <= rhs? %s\n", lhs <= rhs ? "true" : "false");
}
EOF
g++ test_ver.cpp -o test_ver && ./test_ver
prints lhs <= rhs? falseNo, it works. It's just non-obvious that it does due to the reliance on 4 levels of braces.
It is equivalent to the following:
lhs.Major < rhs.Major
or (lhs.Major == rhs.Major and lhs.Minor < rhs.Minor)
or (lhs.Major == rhs.Major and lhs.Minor == rhs.Minor and lhs.Patch <= rhs.Patch)
Deduplicating (lhs.Major == rhs.Major) decreased readability enough to be confusing.There is so many ways to write this comparison that after a couple of times you really wish there were something in the standard library to help you so that you could write e.g.
bool operator<=(version lhs, version rhs) {
return std::tie(lhs.Major, lhs.Minor, lhs.Patch) <= std::tie(rhs.Major, rhs.Minor, rhs.Patch);
}
Wait, there is! And Python has something like this too, even more laconic: you don't need to write "std::tie", naked parentheses are enough.And Microsoft jumped from Windows 8.1 to 10 to avoid breaking applications they assume “first digit is 9 means Windows 9x”. And possibly to catch up with Mac OS X 10.x.
Re:Sentimental Versioning
by SAI_Peregrinus on Monday October 12, 2020 @11:20AM
(#24755293)
1v12 is greater than 1v2. The issue is the "." looks like a radix point, so people think they're decimal numbers. Pick some other separator and that confusion goes away (don't use ",", since that's a radix point for many languages).
Usually there's a 3rd type (patch versions):
"This update fixes important bugs and will almost certain work if the previous version did"
...but you should test anyway in case we've introduced a regression or you depend on behaviour we've decided was a bug.
99% of people using SemVer actually only have two types of change:
1. "Updating will probably work, but you should test anyway in case we've introduced a regression or you depend on behaviour we've decided was a bug"
2. "Updating might not work, depending on which features you're using, but you should test anyway and you'll be forced to update eventually anyway"
Given users have to respond in the same way to both, why adopt a versioning system that claims 1.12 is greater than 1.2 ?