In addition to that, it's not stated in the documentation whether a Nim bool is the same as a C/C++ bool, so it's not clear if we should use the Nim bool to wrap a C/C++ function that takes or returns a C/C++ bool, or if we should use something like
type
CBoolImpl = distinct uint8
cbool* {.importc: "bool", header: "<stdbool.h>".} = CBoolImpl
let
CTrue* {.importc: "((bool)(true))", header: "<stdbool.h>".}: cbool
CFalse* {.importc: "((bool)(false))", header: "<stdbool.h>".}: cbool
#This is incomplete. Don't actually use it.
In the Cython language, there used to be a similar issue, which is solved by having different bool types: cpython.bool (which is the same as a bool in Python), libcpp.bool (which is the same as a bool in C++), and bint (which is the default, a bool in Python and an int in C). So I think having different bool types could be a viable way. Another way is to update the documentation.
I only use this type internally in my C library wrappers. I export only Nim types. That's why I don't define C-style TRUE/FALSE at all. I use converters.
type cbool = distinct byte
converter from_cbool(b: cbool): bool = b != 0
converter to_cbool(b: bool): cbyte = b.cbyte
And you don't have to worry about C99 bool size constraints, the standard does not require an implementation to have even fixed width types. How many such implementations are still alive today? Close to none.
The manual clearly states: "The size of the bool type is one byte."
In practice it's always compatible with C++ and not with C. But that's not a big problem as C programmers do not understand types anyway and everything uses int (aka cint) instead.