”the only machine the author could find using non-two’s complement are made by Unisys, and no counter-example was brought by any member of the C++ standards committee. Nowadays Unisys emulates their old architecture using x86 CPUs with attached FPGAs for customers who have legacy applications which they’ve been unable to migrate. These applications are unlikely to be well served by modern C++, signed integers are the least of their problem. Post-modern C++ should focus on serving its existing users well, and incoming users should be blissfully unaware of integer esoterica.”
That led to the decision that ”Signed Integers are Two’s Complement” in C++ 20.
That makes it too easy to write portable code :-)
One advantage of pinning down two's complement is that the result of arithmetic is known down to the bit level, even when it overflows.
Also, certain bit operations. For instance, if we know that the representation is two's complement, we are justified in expecting sign extension on a right shift: the sign bit is repeated to fill the top bit positions. (The shift of a signed number should be "arithmetic"; that of unsigned "logical".)
Also, truncations (converting a wider type to a narrower type) should have predictable results. For instance if we chop the value -238 to 8 bits, we should get 18, because -238 is 0xFF..FF12, which truncates to 0x12.
Using signed arithmetic means that you can actually trap on overflow and catch these bugs (using fuzzing for instance).
Chandler explained it nicely in his CPPCon 2016 talk "Garbage In, Garbage Out: Arguing about Undefined Behavior...". I encourage to watch the full talk but here is one relevant example:
https://youtu.be/yG1OZ69H_-o?t=2006
And here he mentions how Google experimented with this internally: https://youtu.be/yG1OZ69H_-o?t=2249
> Using signed arithmetic means that you can actually trap on overflow and catch these bugs (using fuzzing for instance).
The reason you can't do this for unsigned types is not simply that their modulo-reducing behavior is well-defined, but that it is actually exploited in correct code, which then leads to false positives if the behavior is trapped.
But the overflow behavior of signed types is also exploited.
Either one could be usefully caught with tools, if the tools can simply be told where in the program to ignore false positives. If I'm using unsigned types in foo.c, with no intention of relying on the modulo wrapping, I should be able to tell the tool to report all unsigned wrapping occurrences in just foo.c without caring what is done with unsigned types elsewhere in the program or its dependent libraries.
All that said, I believe unsigned types should be eschewed as much as possible because thy have an unacceptable discontinuity right to the left of zero. Suppose A, B and C are small positive integers close to zero, say all less than a hundred or so. Then given
A + B > C
and knowing elementary school algebra, I can rewrite that as: A > B - C
But I can do that in the actual code only if the type is signed. I cannot do that if it is unsigned, because C might be greater than B, and produce some huge number. This happens even though I'm working with harmless little numbers less than around a hundred.We should prefer to work with integers that obey basic algebraic laws, at least when their magnitudes are small, so that we don't have to think about "is that test phrased in the right way, or do we have a bug here?"
In any higher level language than C, we should have multi-precision integers. I no longer consider any non-C language viable if it doesn't. If I'm reading the manual for some new supposedly high level language and come across a statement like "integers are 64 bits wide in Fart, but a clumsy library called Burp provides bolted-on bignums", I stop reading, hit the back button and don't come back.
for (int i = 0; i < bound; i++)
in an LP64 environment (i.e., one where the native machine word is 64 bits but int is 32 bits, as is the case in most modern compilers targeting most modern architectures), it allows i to be represented by a native machine word, increasing performance.You can, and people constantly do, argue about whether this is worth it, but I suspect it's the primary reason why a lot of the committee didn't want to change this behavior.
The current fashion is that we like programs that assume int is 32 bits, and don't like ones that assume wraparound arithmetic.
> Status-quo If a signed operation would naturally produce a value that is not within the range of the result type, the behavior is undefined. The author had hoped to make this well-defined as wrapping (the operations produce the same value bits as for the corresponding unsigned type), but WG21 had strong resistance against this.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p090...
Forced to choose, I'd rather see signed overflow be required to abort the program or throw an exception than wrap.
What will get you off the C++ drug easily is Lisp.
Once I discovered Lisp, C++ had no place in my "personal spectrum" any more, but C (including the C-like subset of C++) still did. Well, it wasn't so sudden, mind you. More like: the more Lisp I knew, the less interest I had in C++.
(Idiotic lambda implementations and whatnot will not woo me back, sorry.)
My first drug was Turbo Pascal, from 4.0 all the way to TPW 1.5.
Naturally the only thing C had going for it was being a language with an OS. As in regard to its features it was already unatractive in 1990 for me.
Thankfully in 1993, C++ was already an option that also came with an OS, as it became adopted by OS vendors in their SDKs.
C++ stagnated for a long time, but IMO Boost's metaprogramming reinvigorated the language and community.
Now they are following through with concepts, metaprograms that can do everything runtime programs can do, and soon reflection. Wow.
It only goes up to C++14 but there's not all that much that's new in C++17. C++20 looks like it's going to be a bigger update, hopefully Scott will come out with a new revision of Effective C++ to address the changes.
[1] https://github.com/tiny-dnn/tiny-dnn/blob/master/tiny_dnn/no...
[1] https://speakerdeck.com/olvemaudal/42-silly-ways-to-say-hell...
Are there any numbers/graphs on how many proposals are being submitted over time? I feel like they are exploding.
https://www.reddit.com/r/cpp/comments/9vwvbz/2018_san_diego_...
It'll be nearing a decade of "next release" now as it's own TS and near two decades of proposal since TR2.
Edit: The Reddit trip report lists 23 as optimistic and 26 as the conservative.
Would make bootstrapping some of these new features to a usable level much quicker.
Speaking as a dev that needs features to span 3 major compilers (clang/gcc/vs) before I can use them.
http://www.plumhall.com/suites.html
https://www.opengroup.org/testing/testsuites/perenial.htm
https://peren.com/pages/cppvs_set.htm
Ah just needing the support across 3 major compilers!
I guess you haven't enjoyed the glory days of writing portable C, C++ or Pascal code during the 1990's.
I note that there is some sharing of test-suites between the different compiler vendors, certainly they occasionaly run their compilers against some of each others test.
But a central shared resource that is updated by multiple people to catch edge cases would be first prize.
(And hopefully, seeded by the proposal authors, to act as a useful starting point)
The only people that can keep up are the hobbyists and the language purists. It's become a circle jerk and that's a shame because they are modernizing themselves out of existence, in my opinion. No one in real software can keep up with the biannual changes and it's getting to the point where migrating to another language like Go or Java is a lot more stable and less risky.
The more recent additions are more along the lines of "I can't believe that wasn't already in the standard!" rather than new things to learn.
Or you can go on and, whenever you have a question about c++, start googling it as "c++17 <question>" instead of "c++ <question>" to find more modern answers, you might actually like, as some of them are safer to use, e.g., less off-by-one errors, and easier to read.
I personally felt overwhelmed from all the changes, but watching some videos I saw syntax I really liked and wanted to use! For the most part it was easy to understand, too. Being able to gradually change (at least in smaller projects) was a really nice experience.
Programming languages are just like any other software product.
Yeah, that's the problem isn't?
You do in fact need damn seat belts to cope with all the changes to what used to be a very predictable and simple to understand language.
However it isn't really that much bigger than Java, .NET + VB/C#/F#, Python, Ada, Common Lisp,... when one looks at the size of printed language, library and implementation specifications.
It is just that others are more beginner friendly and most devs forget they have a pile of features on their own languages as well.