Re:Sentimental Versioning
by brabel on Monday October 12, 2020 @07:14AM
(#24753263)
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.
[ Parent
| on HN ]
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.