Hacker News new | ask | show | jobs
by Aardappel 2383 days ago
Generally a wonderful set of minimalistic rules, much could carry over beyond C.

Except for: "OMG-API-3: Unsigned integers are preferred over signed".. I feel they're on the wrong side of history with this one.

"Prefer unsigned" only works if you can do 99% of your codebase this way, which, besides LLVM, probably doesn't work for anyone. Having a codebase that is 99% signed is much more feasible. The worst is a codebase with plenty of both, which will be guaranteed endless subtle bugs and/or a ton of casts. That's what they'll end up with.

Apparently the C++ committee agrees that size_t being unsigned was a huge mistake (reference needed), and I would agree. Related discussion: https://github.com/ericniebler/stl2/issues/182 https://github.com/fish-shell/fish-shell/issues/3493 https://wesmckinney.com/blog/avoid-unsigned-integers/

Even LLVM has all this comical code dealing with negative values stored in unsigneds.

The idea that you should use unsigned to indicate that a value can't be negative is also pretty arbitrary. Your integer type doesn't represent the valid range of values in almost all cases, enforcing it is an unrelated concern.

3 comments

I can see where they're coming from, signed integers come with all sorts of caveats in C and C++ from overflow being undefined behaviour (yet modulo-math often makes sense when integers are used as array indices) to bit twiddling surprises. "Almost always unsigned" sounds like a good rule to me to avoid such pitfalls, especially when 'common math stuff' is usually done with floats or special fixed-point formats.
Overflow being UB is not something you run into easily with typical math, index and size uses (not as often as your run into unsigned issues, in my experience). Yes, bit-twiddling should be unsigned, but it is very easy to make this code isolated, and convert from signed values storing these bits, if necessary.

But I am going to defer to authority here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p142...

We actually had a debate about this. I was initially in favor of "signed as default", but I acquiesced.

In retrospect, I think I was wrong and that "unsigned as default" works better.

I think the domain is important here. We're building a game engine, so there's actually plenty of bit fiddling. We also make use of the "overflow wraparound" of unsigneds in a lot of places.

I think in our case having 99 % unsigned is more feasible than having 99 % signed. There are actually not many things that we would need to use a signed integer for.

FYI, in our codebase right now we have

10038 uint32_t 123 int32_t 7843 uint64_t 58 int64_t

So at the moment we're actually 98.998 % unsigned.

I know it's not 99 %, but it's pretty close :)

Well, you have the facts to back it up, so indeed it can work for you. I'd say it requires quite some commitment to push it that far though, and I still would think it's not the right default for almost all teams. Impressive you made it work :)
I actually like the distinction between std::size_t/std::ptrdiff_t (and even better std::vector's ::size_type and difference_type ). It makes the intent very clear.

It helps that I get to compile all my code -Wconversion.