
OMG: Our Machinery Guidebook - onekorg
https://ourmachinery.com/files/guidebook.md.html
======
Aardappel
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/ericniebler/stl2/issues/182)
[https://github.com/fish-shell/fish-
shell/issues/3493](https://github.com/fish-shell/fish-shell/issues/3493)
[https://wesmckinney.com/blog/avoid-unsigned-
integers/](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.

~~~
flohofwoe
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.

~~~
Aardappel
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...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2019/p1428r0.pdf)

------
vietjtnguyen
Quick typo under OMG-CODEORG-2:

    
    
        #pragma once
    
        #ifdef __cpluspus // <-- should be __cplusplus
        extern "C" {
        #endif
    
        #include "api_types.h"
    
        // ...
    
        #ifdef __cplusplus
        }
        #endif
    
    

Can't say I'm a fan of OMG-CODEORG-3, however, it sounds like compilation time
is a key metric for them.. I prefer a John Lakos style "physical components"
set up which emulates a type-as-module inclusion style. At least OMG-CODEORG-3
clearly states that include order becomes important as a result.

~~~
midnightclubbed
Agree, CODEORG-3 adds a bunch of pain. There's a reason other languages don't
have headers but since C programmers have to live with them can't I just
include the single relevant header and move on with writing my code. Yes there
is a shared cost to that (compile time) but '#pragma once' is well supported
and futzing with header order is a non trivial time-sink too.

On the same lines the template 'cute tricks' are where you get your
performance, stability and readability from C++. I definitely agree that you
should drop into assembly to see what the compiler is doing with your code but
that can and should apply to heavily templated code too.

~~~
bobdobbs666
Pragma once only prevents double inclusion within the translation unit.

On large projects bad header hygiene can cause significant compilation
overhead.

------
bradknowles
NB: For those who are not aware, ourmachinery.com is a game engine development
company.

------
mwcremer
_I.e., use a double parameter that specifies seconds, instead of an uint32_t
that specifies milliseconds._

This can have surprising and sometimes unpleasant consequences; see
[https://0.30000000000000004.com](https://0.30000000000000004.com)

~~~
United857
Better yet, use std::chrono. Yes, it's C++. But this is an example of how
properly applied bits from C++ can make things easier to reason about and
type-safe, rather than "let's avoid C++ as much as possible".

No ambiguity for the programmer as to what the underlying units are, and no
unnecessary int/float conversions. All the book-keeping and conversions are
taken care of by the compiler with zero run-time size or perf overhead.

~~~
flohofwoe
std::chrono is a terribly overengineered API even for the STL, and many game
companies have banned parts or all of the STL for good reasons (usually not
std::chrono related though).

Using an uint64_t (instead of uint32_t or double) to carry "opaque ticks", and
a handful conversion function to convert to real-world time units is fine and
just a few lines of code.

~~~
niklasgray
This is exactly what we do.

------
mistrial9
the layout and typesetting on this looks good in Firefox 70!

view-
source:[https://ourmachinery.com/files/guidebook.md.html](https://ourmachinery.com/files/guidebook.md.html)

<meta charset="utf-8" emacsmode="- _\- markdown -_ -">

~~~
corysama
Formatted by [http://casual-effects.com/markdeep/](http://casual-
effects.com/markdeep/)

------
Animats
Objects as structs with function pointers? 1990 is calling. I'm not a huge C++
fan, but trying to emulate C++ concepts in C is kind of lame at this late
date.

~~~
rootlocus
Just goes to show C++ failed the zero overhead principle.

~~~
Animats
If you don't have virtual functions, a C++ object is just an struct associated
with static function links.

------
rootlocus
OMG-DESIGN-4: Explicit is better than implicit

Ahh, straight out of the zen of Python!

    
    
        $ python -c "import this"

~~~
michaelcampbell
Django: "hold my beer"

