EDIT: Which is the solution they apparently implemented, converting signed to unsigned at some higher layer.
EDIT: Which is the solution they apparently implemented, converting signed to unsigned at some higher layer.
"You should not use the unsigned integer types such as uint32_t, unless there is a valid reason such as representing a bit pattern rather than a number, or you need defined overflow modulo 2^N. In particular, do not use unsigned types to say a number will never be negative. Instead, use assertions for this." [0]
[0]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.h...
"Never use a signed type for a number that can never be negative"
One of my pet peeves is developers using int (instead of unsigned ints) for primary keys in database tables.
"SQL only specifies the integer types integer (or int), smallint, and bigint." http://www.postgresql.org/docs/9.3/static/datatype-numeric.h...
In this case, it makes absolutely no difference at all. It could be argued that writing unsigned int would make the code slightly harder to read. That said, I like to use stdint.h and unint32_t would, I think, not have any drawbacks.
> there is lot of code out there with interfaces expecting signed ints even though they should using uint
That's not a good reason to not use unsigned integers, it's a zero-overhead cast from unsigned to signed (at the risk of overflowing into the negative).
Using uint limits the optimizer...
Every time I see someone mention the optimization argument for signed integers I ask for examples and I've yet see a good one.
for (int i = x.size() - 1; i >= 0; i--) ...
for (int i = 0; i < x.size() - 1; i++) if (x[i] < x[i+1]) ...
Both will blow up badly with unsigned ints.(Well, to be fair, both will blow up with signed ints if x.size() is greater than 2G, so it's a matter of expectations.)
for( size_t i = x.size(); i-- > 0; ) ...Remember that a for loop does something like this behind the scenes:
size_t i = x.size();
while( i-- > 0 )
{
// your code which needs backwards iteration here
; // do nothing because there is no third statement
}Still, the trick makes it look suspect and that's an argument against using it.
This is true. The code is confusing to people not used to it. A workaround could be to hide this code inside a macro, so people not interested in digging into the code would take the macro's word:
#define REVERSE_LOOP( x, i ) for( size_t i = x.size(); i-- > 0; )
But unfortunately, that doesn't help with the fear that people has against unsigned types.That yields compiler warnings for signed vs unsigned then, no?
// count up
std::size_t i = 0;
while (i != 10)
{
std::cout << i << "\n";
++i;
}
// count down
std::size_t i = 10;
while (i != 0)
{
--i;
std::cout << i << "\n";
}
After initialization a for statement repeats "test; body; advance", this is ideal for counting up loops, but what we need for counting down loops is "test; advance; body". Since C/C++ do not provide the latter as a primitive you have to use a while loop as shown above. Using a signed integer to shoehorn a counting down loop into a for statement at the cost of 1/2 your range is a hack IMO. Note that when working with iterators you have to resort to a while statement as iterating past begin is UB.I'm pretty sure that it's just because "int" is one word and "unsigned int" is two, plus more than twice the characters. I suspect if "int" defaulted to "unsigned int" and you'd have to specify signed ints explicitly, the taboo would be reversed.
Never underestimate the power of trivial inconveniences.
There's example code on the CERT secure coding guidelines here (look under 'Substraction'):
https://www.securecoding.cert.org/confluence/display/seccode...
Writing safe code to calculate the absolute difference between two unsigned integers is much less hairy: max(x,y) - min(y,x).
Really, working directly in fixed-precision arithmetic is absurd. In order to be able to rely on its correctness with any degree of certainty, you need to very carefully track each operation and its bounds, at which point you may as well have just used arbitrary-precision types, explicitly encoded your constraints, and had the compiler optimize things down to scalar types when possible, warning when not.
Fixed-precision arithmetic has one main advantage over arbitrary-precision arithmetic: it is more time- and space-efficient. This advantage only applies if the fixed-precision arithmetic is actually correct and the fixed-precision arithmetic meets some concrete time or space constraint which arbitrary-precision arithmetic fails to meet. It generally takes time and effort to demonstrate that these conditions hold; because one can rely on the correctness of arbitrary-precision arithmetic without doing so, arbitrary-precision arithmetic should then generally be the default choice.
This assumes that you care about making relatively strong guarantees about the correctness of your programs. If for some reason you don't, then sure, use ints and whatnot for everything. If you do, though, I suspect you'll find that it's easier to track down a performance bottleneck caused by using bignums than an obscure bug triggered by GCC applying an inappropriate optimization based on overflow analysis.
if (index < 0) { /* error */ }
I die a little inside.Seems like a pretty ignorant pet peeve considering that's the only option for every database that doesn't auto-corrupt data.
Having a negative pkey space is actually useful. In LSMB we reserve all negative id's for test cases, which are guaranteed to roll back. This has a number of advantages including the ability to run a full test run on a production system without any possibility of leaving traces in the db.
1) If you don't need negative numbers, use unsigned integers.
2) If you don't need the extra positive range of unsigned integers (or defined wrapping), use signed.
You advocate (1), but C is generally based on (2), with the default int being signed, and many standard functions using plain int.
[0] though several do support UUIDs, which are essentially unsigned 128-bit ints, and which (with a well-selected generation mechanism) are better as server-assigned surrogate keys than sequential integers, signed or unsigned, anyway.
Furthermore, casting uintx_t to int and back again while using shared libraries is a huge pain in the ass and can waste a lot of programmer time that would be better spent elsewhere, especially when working with ints and uints together (casting errors, usually in the form of a misplaced parenthesis, are pretty small and can take a very long time to find).
2 billion survey results was never going to happen. 32,767 would have been fine as well except to compound the issue ops pointed the production site at the test database.
uintN_t (and intN_t) are MORE portable and cross platform than int in the sense that you get much better guarantees about it's size and layout.
Furthermore, int is NOT the size of the register (x64 commonly has an int of 32 bits) so any updating you'd have to do to uintN_t, you'd have to do to int as well. Regardless, I can't imagine why you'd need to do any updating in the first place - it's perfectly valid to stick a uint32_t in a 64 bit register.
> nevermind the fact that int is usually more optimized than uint these days
Where are ints more optimized than uint? Not in the processor, not in the compiler (modulo undefined behavior on overflow) and not in libraries.
However, I think this is a problem. The expected value ranges of your variables don't change just because your memory bus got wider - maybe you can use more than 4GB memory in a process now, but it's a mistake to plan for single array indexes being more than 32bit.
If you do try to be more flexible, I'm sure this would introduce more bugs than the forward-compatibility it'd add. Especially if 'int' is smaller than on the platform you tested on. That's why languages like Swift, Java, C# always have 32-bit int on every platform.
> casting errors, usually in the form of a misplaced parenthesis, are pretty small and can take a very long time to find
Agreed, but writing casts also adds unwarranted explicitness. What if someone made a typo and put the wrong type in the cast? How do you tell what's right? What if you change the type of the lvalue or the casted value? Now you have to think about each related cast you added.
What's the alternative? Well, the compiler should just know what you mean…
This is why we have uint_least8_t and friends. In fact, int is really just another int_least16_t.
> Furthermore, casting uintx_t to int and back again while using shared libraries is a huge pain in the ass and can waste a lot of programmer time that would be better spent elsewhere
Could you give an example? It sounds like you're just talking about performing the casts, which shouldn't take much effort at all as indiscriminately as C casts about integral values.
* dynamically test your program with ubsan to be sure they really don't happen, and then
* let your compiler optimize with the knowledge that integers won't overflow.
This last one eliminates maybe half the possible execution paths it can see, and loop structure optimizations practically don't work without it.
On the other hand, unsigned overflows? Some of those are bad, but some are fine, right? How will an analyzer know which is which?
Some notable libraries like C++ STL want you to write loops with unsigned math (size_t iterations), but those people invented C++, so why would you trust them with anything else?
If a function must-overflow the optimizer (hopefully) replaces the entire thing with an abort under ubsan, so you could look for that. But that's probably not sensitive enough.
And if the function is just 'x + 1' that may-overflow, but it's not important.
Maybe you want this: http://pdos.csail.mit.edu/papers/stack:sosp13.pdf
... and now I realize you may be correct, and that it's probably inevitable that a viewcount will not only exceed the total number of people alive, but will double or even quadruple it. Our total population is actually about 100 billion, but only ~7% of us are still alive.
The shadows of the dead will be forever enshrined as YouTube view counts. Our shadows.
"We always overestimate the change that will occur in the next two years and underestimate the change that will occur in the next ten." - Bill Gates
[One problem with unsigned integers in protocol buffers is that some supported languages like Python have no concept of signed/unsigned integers. Which is why for example Thrift does not support that distinction. This has nothing to do with C++ though.]
You can still implement range checks to enforce that the numbers are in the correct domain. It's not that much of a problem.
This is more of a problem in a statically typed language like Java, because it means there is no native data type to map protobuf's unsigned types to. In Python this doesn't matter as much because numbers will automatically promote themselves to bigints.
Edit: Now I realize that would mean Google couldn't have made this joke. But I am still not sure this was foreseen by Youtube devs from day one.