Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

(self-reply) One more thing.

> I could use _Bool, but I’d rather stick to a natural word size and stay away from its weird semantics.

This is even more subjective, but personally I like _Bool's semantics. They mean that if an expression works in an `if` statement:

    if (flags & FLAG_ALLOCATED)
then you can extract that same expression into a boolean variable:

    _Bool need_free = flags & FLAG_ALLOCATED;
The issue is that `flags & FLAG_ALLOCATED` doesn't equal '0 if unset, 1 if set', but '0 if unset, some arbitrary nonzero value if set'. (Specifically it equals FLAG_ALLOCATED if set, which might be 1 by coincidence, but usually isn't.) This kind of punning is fine in an `if` statement, since any nonzero value will make the check pass. And it's fine as written with `_Bool`, since any nonzero integer will be converted to 1 when the expression is implicitly converted to `_Bool`. But if you replace `_Bool` with `int`, then this neither-0-nor-1 value will just stick around in the variable. Which can cause strange consequences. It means that

    if (need_free)
will pass, but

    if (need_free == true)
will fail. And if you have another pseudo-bool, then

    if (need_free == some_other_bool)
might fail even if both variables are considered 'true' (i.e. nonzero), if they happen to have different values.

_Bool solves this problem. Admittedly, the implicitness has downsides. If you're refactoring the code and you decide you don't really need a separate variable, you might try to replace all uses of `need_free` with its definition, not realizing that the implicit conversion to _Bool was doing useful work. So you might end up with incorrect code like:

    if ((flags & FLAG_ALLOCATED) == true)
Also, if you are reading a struct from disk or otherwise stuffing it with arbitrary bytes, and the struct has a _Bool, then you risk undefined behavior if the corresponding byte becomes something other than 0 or 1 – because the compiler assumes that the implicit conversion to 0 or 1 has been done already.


This is all very good and very, ahem, true. But (and it's a big butt);

if (need_free == true)

Is such a horrible code smell to me. You have a perfectly good boolean. Why compare it to a second boolean to get a third boolean?

if (need_free)

or

if (!need_free)

for the opposite case is so much better.

I will admit that in my world this leaves

if (need_free == some_other_bool)

as something I don't have a particularly comfortable way of doing safely.


Better example:

  #define FLAG_63 (1ULL << 63)
  long long flags = FLAG_63;
In this case,

  if (flags & FLAG_63) pass();
will pass, but

  typedef int BOOL;
  BOOL set = flags & FLAG_63;
  if (set) pass();
won't pass, due to truncation.

Question: Would you argue that a datatype that holds the smallest (1-bit) datum should be as wide as the largest integer type just to handle such cases?

If so, that would be highly inefficient for storage purposes. Note that Win32 has 32-bit BOOL type, but internally NT uses 8-bit BOOLEAN type to store bools in structures.


  > if (need_free == true)
  > Is such a horrible code smell to me. You have a perfectly good boolean. Why compare it to a second boolean to get a third boolean?
  > if (need_free)
You are probably interested if the `need_free` flag is set to true, and not if `need_free`. It is true that `if (need_free)` has the same behaviour, but it is some steps farther from what you are interested in.


This feels to me like you're introducing the same unnecessary extra layer into your text as in the original code. I mean, why not

"You are probably interested in whether it's true that the 'need_free' flag is set to true"

leading to

> if ((need_free == true) == true)

? Answer: because that extra layer of indirection adds nothing, and just gives you a bit of extra cognitive load and an extra opportunity to make mistakes. I think the same is true about going from "need_free" to "need_free is set to true".

(This becomes less clear if you have variable names like 'need_free_flag'. I say: so don't do that then! It's almost always appropriate to give boolean values and functions that return boolean values names that reflect what it means when the value is true.)


Couldn't we do it like (!need_free == !some_other_bool)?


You can go the php way and do if (!!need_free)


Clever, I like it.


For:

  if (need_free == some_other_bool)
you could use:

  if (!need_free ^ some_other_bool)
if you're using _Bool.


I always just use !! for this case.


Yes, I do this as well. It looks a little funny if you're not used to it, I suppose.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: