I found a comment today in a source file:
// - no longer compare BOOL against YES (dangerous!)
Is comparing BOOL
against
All this is true, but there are valid counter arguments that might be considered:
— Maybe we want to check a BOOL is actually YES or NO. Really, storing any other value than 0 or 1 in a BOOL is pretty incorrect. If it happens, isn't it more likely because of a bug somewhere else in the codebase, and isn't not explicitly checking against YES just masking this bug? I think this is way more likely than a sloppy programmer using BOOL in a non-standard way. So, I think I'd want my tests to fail if my BOOL isn't YES when I'm looking for truth.
— I don't necessarily agree that "if (isWhatever)" is more readable especially when evaluating long, but otherwise readable, function calls,
e.g. compare
if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]]) {}
with:
if (![myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]]) {}
The first is comparing against true, the second against false and it's hard to tell the difference when quickly reading code, right?
Compare this to:
if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]] == YES) {}
and
if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]] == NO) {}
…and isn't it much more readable?
Again, I'm not saying one way is correct and the other's wrong, but there are some counterpoints.
When the code uses a BOOL
variable, it is supposed to use such variable as a boolean. The compiler doesn't check if a BOOL
variable gets a different value, in the same way the compiler doesn't check if you initialize a variable passed to a method with a value taken between a set of constants.
You should never compare booleans against anything in any of the C based languages. The right way to do it is to use either:
if (b)
or:
if (!b)
This makes your code much more readable (especially if you're using intelligently named variables and functions like isPrime(n)
or childThreadHasFinished
) and safe. The reason something like:
if (b == TRUE)
is not so safe is that there are actually a large number of values of b
which will evaluate to true, and TRUE
is only one of them.
Consider the following:
#define FALSE 0
#define TRUE 1
int flag = 7;
if (flag) printf ("number 1\n");
if (flag == TRUE) printf ("number 2\n");
You should get both those lines printed out if it were working as expected but you only get the first. That's because 7 is actually true if treated correctly (0 is false, everything else is true) but the explicit test for equality evaluates to false.
Update:
In response to your comment that you thought there'd be more to it than coder stupidity: yes, there is (but I still wouldn't discount coder stupidity as a good enough reason - defensive programming is always a good idea).
I also mentioned readability, which is rather high on my list of desirable features in code.
A condition should either be a comparison between objects or a flag (including boolean return values):
if (a == b) ...
if (c > d) ...
if (strcmp (e, "Urk") == 0) ...
if (isFinished) ...
if (userPressedEsc (ch)) ...
If you use (what I consider) an abomination like:
if (isFinished == TRUE) ...
where do you stop:
if (isFinished == TRUE) ...
if ((isFinished == TRUE) == TRUE) ...
if (((isFinished == TRUE) == TRUE) == TRUE) ...
and so on.
The right way to do it for readability is to just use appropriately named flag variables.
The problem is that BOOL is not a native type, but a typedef:
typedef signed char BOOL;
#define YES (BOOL)1
#define NO (BOOL)0
As a char, its values aren't constrained to TRUE
and FALSE
. What happens with another value?
BOOL b = 42;
if (b)
{
// true
}
if (b != YES)
{
// also true
}