user156027
user156027

Reputation:

Is comparing a BOOL against YES dangerous?

I found a comment today in a source file:

//  - no longer compare BOOL against YES (dangerous!)

Is comparing BOOL against YES in Objective-C really that dangerous? And why is that?

Can the value of YES change during runtime? Maybe NO is always 0 but YES can be 1, 2 or 3 - depending on runtime, compiler, your linked frameworks?

Upvotes: 7

Views: 9248

Answers (4)

Russell Quinn
Russell Quinn

Reputation: 1350

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.

Upvotes: 2

paxdiablo
paxdiablo

Reputation: 881323

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.

Upvotes: 11

avpaderno
avpaderno

Reputation: 29669

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.

Upvotes: 0

Michael Petrotta
Michael Petrotta

Reputation: 60902

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
}

Upvotes: 17

Related Questions