Is BOOL versus YES dangerous?

Today I found a comment in the source file:

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

Is comparing BOOL to YES in Objective-C really dangerous? And why so?

Can the YES value change at runtime? Maybe NO always 0 , but YES can be 1 , 2 or 3 - depending on runtime, compiler, related frameworks?

+6
comparison objective-c boolean
source share
4 answers

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 

Like char, its values ​​are not limited to TRUE and FALSE . What happens with a different meaning?

 BOOL b = 42; if (b) { // true } if (b != YES) { // also true } 
+17
source share

You should never compare booleans with anything in any of the C languages. The right way to do this is to use either:

 if (b) 

or

 if (!b) 

This makes your code more readable (especially if you use intelligently named variables and functions like isPrime(n) or childThreadHasFinished ) and are safe. The reason is something like:

 if (b == TRUE) 

is not so safe that in fact there are a large number of b values ​​that will be evaluated as 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 of these lines printed if they work as expected, but you only get the first one. This is because 7 is truly true if handled correctly (0 is false, everything else is true), but an explicit test for equality is evaluated as false.

Update:

In response to your comment, that you thought that this would be more than the stupidity of the encoder: yes, there is (but I still will not reduce the stupidity of the encoder as a good enough reason - defensive programming is always a good idea).

I also mentioned readability, which is pretty high on my list of desired features in the code.

The condition must be either 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 stay:

 if (isFinished == TRUE) ... if ((isFinished == TRUE) == TRUE) ... if (((isFinished == TRUE) == TRUE) == TRUE) ... 

etc.

The right way to do this for readability is to simply use the appropriate flag variable names.

+10
source share

All of this is true, but there are valid counter arguments that could be considered:

- Perhaps we want to check the BOOL in fact, YES or NO. Indeed, storing any other value other than 0 or 1 in BOOL is pretty wrong. If this happens, is it probably not due to an error somewhere else in the code base, and does not explicitly check YES, simply masking this error? I think this is more likely than a sloppy programmer using BOOL in a non-standard way. So, I think I would like my tests to fail if my BOOL is not YES when I search for the truth.

- I do not always agree that "if (isWhatever)" is more readable, especially when evaluating long, but in other cases readable function calls,

eg. compare

 if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]]) {} 

from:

 if (![myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]]) {} 

The first is compared to true, the second to false, and it’s hard to tell the difference when quickly reading the code, right?

Compare this to:

 if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]] == YES) {} 

and

 if ([myObj doThisBigThingWithName:@"Name" andDate:[NSDate now]] == NO) {} 

... and is it more readable?

Again, I am not saying that one of the methods is correct and the other is incorrect, but there are some counterpoints.

+1
source share

When the code uses the BOOL variable, it is intended to use a variable such as a boolean. The compiler does not check whether the BOOL variable receives a different value, just as the compiler does not check whether the variable passed to the method with the value taken between the set of constants is initialized.

0
source share

All Articles