[libvirt] proposal: allow use of "bool": HACKING: discuss C types

Hello, I don't want to make waves, but I do care about certain aspects of code quality, so... I propose to allow (encourage, even) the use of the standard C99 type, bool, in libvirt, but not in public interfaces[1]. There are already uses in cgroup.c and xmlrpc.c, as well as those in the gnulib "c-ctype.h" header which is included from many of libvirt's .c files. The motivation is to make the code as readable as possible. When you see the declaration of an "int" variable, member, or function, that type gives you no clue whether it is used as a boolean. If you see a few uses that treat it as boolean, that's still no guarantee, and it may be non-trivial to ensure that there isn't some non-boolean value with a special meaning. However, if you see a "bool" variable, you do have that guarantee. This is one reason to using the tighter, more descriptive type. In addition, if ever you need to go back to using "int", it's trivial to automate the substitution, e.g., -Dint=bool or sed s/int/bool/. On the other hand, it is very hard to automatically identify "int" variables that may safely be converted to "bool". Portability is no problem whatsoever, thanks to gnulib's stdbool module, which ensures that there is a working <stdbool.h> header in the compiler's include path. libvirt even includes/runs a test to ensure that the <stdbool.h> in use (from gnulib or from the system) works properly. Of course, if you agree on principle, we should update HACKING to reflect the policy, so I've taken a shot at that. But if we start talking about using the right type for boolean variables, we can't avoid the more general question of scalars, signedness, etc. And once you mention scalars, you have to mention pointers and const-correctness, so it got longer still. Patch below. Jim [1]: We can use "bool" reliably in libvirt-internal code, due to the fact that it is guaranteed to be compiled with a usable <stdbool.h> header. We cannot make such a guarantee for all applications that compile code including libvirt's public headers, <libvirt.h> and <virterror.h>. P.S. I confess I have a vested interested. I wrote a patch recently that declares a local to be of type "bool", and would like to ensure that policy permits doing that.
From 3c6a9bc0fd043ce9f84e5aaba3cfbc1db0359eb7 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Fri, 12 Dec 2008 09:45:31 +0100 Subject: [PATCH] HACKING: use the right type
--- HACKING | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 46 insertions(+), 0 deletions(-) diff --git a/HACKING b/HACKING index 3945833..511c8cc 100644 --- a/HACKING +++ b/HACKING @@ -91,6 +91,52 @@ Usually they're in macro definitions or strings, and should be converted anyhow. +C types +======= +Use the right type. + +Scalars +------- +If you're using "int" or "long", odds are good that there's a better type. +If a variable is counting something, be sure to declare it with an +unsigned type. +If it's memory-size-related, use size_t (use ssize_t only if required). +If it's file-size related, use uintmax_t, or maybe off_t. +If it's file-offset related (i.e., signed), use off_t. +If it's just counting small numbers use "unsigned int"; +(on all but oddball embedded systems, you can assume that that +type is at least four bytes wide). +If a variable has boolean semantics, give it the "bool" type +and use the corresponding "true" and "false" macros. It's ok +to include <stdbool.h>, since libvirt's use of gnulib ensures +that it exists and is usable. +In the unusual event that you require a specific width, use a +standard type like int32_t, uint32_t, uint64_t, etc. + +Of course, take all of the above with a grain of salt. If you're about +to use some system interface that requires a type like int or ssize_t, +use types for your own variables that match. + +Also, if you try to use e.g., "unsigned int" as a type, and that +conflicts with the signedness of a related variable, sometimes +it's best just to use the *wrong* type, if "pulling the thread" +and fixing all related variables would be too invasive. + +Finally, while using descriptive types is important, be careful not to +go overboard. If whatever you're doing causes warnings, or requires +casts, then reconsider or ask for help. + +Pointers +-------- +Ensure that all of your pointers are "const-correct". +Unless a pointer is used to modify the pointed-to storage, +give it the "const" attribute. That way, the reader knows +up-front that this is a read-only pointer. Perhaps more +importantly, if we're diligent about this, when you see a non-const +pointer, you're guaranteed that it is used to modify the storage +it points to, or it is aliased to another pointer that is. + + Low level memory management =========================== -- 1.6.1.rc2.299.gead4c.dirty

On Fri, Dec 12, 2008 at 09:58:32AM +0100, Jim Meyering wrote:
Hello,
I don't want to make waves, but I do care about certain aspects of code quality, so...
I propose to allow (encourage, even) the use of the standard C99 type, bool, in libvirt, but not in public interfaces[1]. There are already uses in cgroup.c and xmlrpc.c, as well as those in the gnulib "c-ctype.h" header which is included from many of libvirt's .c files.
The motivation is to make the code as readable as possible. When you see the declaration of an "int" variable, member, or function, that type gives you no clue whether it is used as a boolean. If you see a few uses that treat it as boolean, that's still no guarantee, and it may be non-trivial to ensure that there isn't some non-boolean value with a special meaning.
However, if you see a "bool" variable, you do have that guarantee.
I don't particularly like the idea of using the bool type - No system header files use it - Library header files which use a boolean type have nearly all defined their own custom bool types, not using stdbool.h and there's no guarentee that stdbool's idea of 'true' matches the other apps' - We don't use it in the public API, or on the wire for the remote protocol, since it has undefined size. - The GNULIB bool emulation is unable to provide equivlance between C's idea of true (any non-zero value) and the defined 'true' constant (whose value is 1) - Bitfields are more size efficient than bools. In a language like python where there's a fundamental builtin type in the language for 'bool' this it makes sense. In the C world with many many[1] different definitions of bool, true and false it just feels like a world of hurt. The only thing you can ultimately rely on is that a true value is non-zero. Daniel [1] Picking a *tiny* selection of the bool's in my dev box headers /usr/include/xulrunner-sdk-1.9/stable/jritypes.h:typedef enum JRIBoolean { /usr/include/xulrunner-sdk-1.9/stable/nptypes.h: typedef int bool; /usr/include/xulrunner-sdk-1.9/stable/npapi.h:typedef unsigned char NPBool; /usr/include/xulrunner-sdk-1.9/stable/jri_md.h:typedef unsigned char jbool; /usr/include/wine/windows/wtypes.idl:typedef long BOOL; /usr/include/cups/raster.h:typedef enum cups_bool_e /**** Boolean type ****/ /usr/include/lcms.h:typedef int LCMSBOOL; /usr/include/mp4.h:typedef int bool; /usr/include/tss/tpm.h:typedef BYTE TPM_BOOL; /usr/include/tss/platform.h: typedef int8_t TSS_BOOL; /usr/include/tss/platform.h: typedef signed char TSS_BOOL; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
On Fri, Dec 12, 2008 at 09:58:32AM +0100, Jim Meyering wrote:
I propose to allow (encourage, even) the use of the standard C99 type, bool, in libvirt, but not in public interfaces[1]. There are already uses in cgroup.c and xmlrpc.c, as well as those in the gnulib "c-ctype.h" header which is included from many of libvirt's .c files.
The motivation is to make the code as readable as possible. When you see the declaration of an "int" variable, member, or function, that type gives you no clue whether it is used as a boolean. If you see a few uses that treat it as boolean, that's still no guarantee, and it may be non-trivial to ensure that there isn't some non-boolean value with a special meaning.
However, if you see a "bool" variable, you do have that guarantee.
I don't particularly like the idea of using the bool type
- No system header files use it
Of course. Can't use it there for the same reason that we wouldn't use it in libvirt's own public interfaces, as I explained. But public interfaces make up such a small fraction of the code in question that it'd be a shame to impose its restrictions on all the rest.
- Library header files which use a boolean type have nearly all defined their own custom bool types, not using stdbool.h and there's no guarentee that stdbool's idea of 'true' matches the other apps'
This is the same fundamental restriction. "bool" cannot be used in public headers.
- We don't use it in the public API, or on the wire for the remote protocol, since it has undefined size.
Same point.
- The GNULIB bool emulation is unable to provide equivlance between C's idea of true (any non-zero value) and the defined 'true' constant (whose value is 1)
That sounds scary, but isn't an issue in practice. The uses of "true" and "false" are typically only for initialization. IMHO, one should never compare a bool-declared variable to "true" or "false".
- Bitfields are more size efficient than bools.
It's not about size, but rather readability.
In a language like python where there's a fundamental builtin type in the language for 'bool' this it makes sense. In the C world with many many[1] different definitions of bool, true and false it just feels
The number of definitions is because people find it useful to expose the semantics of the type, yet realize that they cannot use that precise name in a header file.
like a world of hurt. The only thing you can ultimately rely on is that a true value is non-zero.
There is no hurt in my experience. It's used extensively in gnulib-using projects, and

On Wed, Dec 17, 2008 at 01:29:02PM +0100, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
On Fri, Dec 12, 2008 at 09:58:32AM +0100, Jim Meyering wrote:
I propose to allow (encourage, even) the use of the standard C99 type, bool, in libvirt, but not in public interfaces[1]. There are already uses in cgroup.c and xmlrpc.c, as well as those in the gnulib "c-ctype.h" header which is included from many of libvirt's .c files.
The motivation is to make the code as readable as possible. When you see the declaration of an "int" variable, member, or function, that type gives you no clue whether it is used as a boolean. If you see a few uses that treat it as boolean, that's still no guarantee, and it may be non-trivial to ensure that there isn't some non-boolean value with a special meaning.
However, if you see a "bool" variable, you do have that guarantee.
I don't particularly like the idea of using the bool type
- No system header files use it
Of course. Can't use it there for the same reason that we wouldn't use it in libvirt's own public interfaces, as I explained. But public interfaces make up such a small fraction of the code in question that it'd be a shame to impose its restrictions on all the rest.
- Library header files which use a boolean type have nearly all defined their own custom bool types, not using stdbool.h and there's no guarentee that stdbool's idea of 'true' matches the other apps'
This is the same fundamental restriction. "bool" cannot be used in public headers.
- We don't use it in the public API, or on the wire for the remote protocol, since it has undefined size.
Same point.
- The GNULIB bool emulation is unable to provide equivlance between C's idea of true (any non-zero value) and the defined 'true' constant (whose value is 1)
That sounds scary, but isn't an issue in practice. The uses of "true" and "false" are typically only for initialization. IMHO, one should never compare a bool-declared variable to "true" or "false".
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol, and that 'true' / 'false' should only be used for initialization I'm fine with the rest of the docs. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

"Daniel P. Berrange" <berrange@redhat.com> wrote: ...
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol, and that 'true' / 'false' should only be used for initialization I'm fine with the rest of the docs.
Thanks. I've done that and will commit the following:
From 6abb25e9a40221dd299b6a136c4f4046fa2f5529 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Fri, 12 Dec 2008 09:45:31 +0100 Subject: [PATCH] HACKING: mention bool and other scalar types, const-correctness
--- HACKING | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) diff --git a/HACKING b/HACKING index e088da8..ba03604 100644 --- a/HACKING +++ b/HACKING @@ -91,6 +91,59 @@ Usually they're in macro definitions or strings, and should be converted anyhow. +C types +======= +Use the right type. + +Scalars +------- +If you're using "int" or "long", odds are good that there's a better type. +If a variable is counting something, be sure to declare it with an +unsigned type. +If it's memory-size-related, use size_t (use ssize_t only if required). +If it's file-size related, use uintmax_t, or maybe off_t. +If it's file-offset related (i.e., signed), use off_t. +If it's just counting small numbers use "unsigned int"; +(on all but oddball embedded systems, you can assume that that +type is at least four bytes wide). +If a variable has boolean semantics, give it the "bool" type +and use the corresponding "true" and "false" macros. It's ok +to include <stdbool.h>, since libvirt's use of gnulib ensures +that it exists and is usable. +In the unusual event that you require a specific width, use a +standard type like int32_t, uint32_t, uint64_t, etc. + +While using "bool" is good for readability, it comes with minor caveats: + - Don't use "bool" in places where the type size must be constant across + all systems, like public interfaces and on-the-wire protocols. + - Don't compare a bool variable against the literal, "true", + since a value with a logical non-false value need not be "1". + I.e., don't write "if (seen == true) ...". Rather, write "if (seen)...". + +Of course, take all of the above with a grain of salt. If you're about +to use some system interface that requires a type like size_t, pid_t or +off_t, use matching types for any corresponding variables. + +Also, if you try to use e.g., "unsigned int" as a type, and that +conflicts with the signedness of a related variable, sometimes +it's best just to use the *wrong* type, if "pulling the thread" +and fixing all related variables would be too invasive. + +Finally, while using descriptive types is important, be careful not to +go overboard. If whatever you're doing causes warnings, or requires +casts, then reconsider or ask for help. + +Pointers +-------- +Ensure that all of your pointers are "const-correct". +Unless a pointer is used to modify the pointed-to storage, +give it the "const" attribute. That way, the reader knows +up-front that this is a read-only pointer. Perhaps more +importantly, if we're diligent about this, when you see a non-const +pointer, you're guaranteed that it is used to modify the storage +it points to, or it is aliased to another pointer that is. + + Low level memory management =========================== -- 1.6.1.94.g9388

On Mon, Jan 05, 2009 at 08:56:08AM +0100, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote: ...
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol, and that 'true' / 'false' should only be used for initialization I'm fine with the rest of the docs.
Thanks. I've done that and will commit the following:
From 6abb25e9a40221dd299b6a136c4f4046fa2f5529 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Fri, 12 Dec 2008 09:45:31 +0100 Subject: [PATCH] HACKING: mention bool and other scalar types, const-correctness
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Dec 17, 2008 at 09:08:36PM +0000, Daniel P. Berrange wrote:
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol,
What's wrong with using it in the wire protocol? XDR provides bool_t (as int) and converts 'bool' in the interface definition to bool_t. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones Read my OCaml programming blog: http://camltastic.blogspot.com/ Fedora now supports 68 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora

"Richard W.M. Jones" <rjones@redhat.com> wrote:
On Wed, Dec 17, 2008 at 09:08:36PM +0000, Daniel P. Berrange wrote:
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol,
What's wrong with using it in the wire protocol? XDR provides bool_t (as int) and converts 'bool' in the interface definition to bool_t.
It's good to know that from portability/correctness standpoints that would work. However, using a 32-bit "int" to transmit a single bit of info is wasteful. How about this clarification to HACKING? diff --git a/HACKING b/HACKING index ba03604..ca39d61 100644 --- a/HACKING +++ b/HACKING @@ -115,7 +115,10 @@ standard type like int32_t, uint32_t, uint64_t, etc. While using "bool" is good for readability, it comes with minor caveats: - Don't use "bool" in places where the type size must be constant across - all systems, like public interfaces and on-the-wire protocols. + all systems, like public interfaces and on-the-wire protocols. Note + that it would be possible (albeit wasteful) to use "bool" in libvirt's + logical wire protocol, since XDR maps that to its lower-level bool_t + type, which *is* fixed-size. - Don't compare a bool variable against the literal, "true", since a value with a logical non-false value need not be "1". I.e., don't write "if (seen == true) ...". Rather, write "if (seen)...".

On Tue, Jan 13, 2009 at 08:34:28AM +0100, Jim Meyering wrote:
"Richard W.M. Jones" <rjones@redhat.com> wrote:
On Wed, Dec 17, 2008 at 09:08:36PM +0000, Daniel P. Berrange wrote:
Ok, if you want to re-post the HACKING file also mentioning that 'bool' shouldn't be used in our public APIs & wire protocol,
What's wrong with using it in the wire protocol? XDR provides bool_t (as int) and converts 'bool' in the interface definition to bool_t.
It's good to know that from portability/correctness standpoints that would work. However, using a 32-bit "int" to transmit a single bit of info is wasteful. How about this clarification to HACKING?
There's no need. The types on the wire are a direct serialization of the types in our public API methods & structs. Since we forbid the use of bool in the public API, we'll never have any need for it on the RPC wire API. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (3)
-
Daniel P. Berrange
-
Jim Meyering
-
Richard W.M. Jones