Of BOOL and YES

It may not be immediately clear that the Objective C BOOL "type" is not actually a boolean type at all. This is a legacy from the original C language, which does not have an intrinsic boolean type (the iPhone GCC C compiler supports the ISO C99 standard which does define a bool type). To clarify, in the system header file objc.h you can see the following:

typedef signed char        BOOL;

From this it is clear that BOOL is actually a signed char type. This has some implications when it comes to using the YES and NO values that are typically assigned to variables of "type" BOOL. If we look a little further down objc.h you will see the following:

1
2
#define YES             (BOOL)1
#define NO              (BOOL)0

So what is the problem with BOOL and YES? In a nutshell, the problem is that variables of type BOOL can contain values other than YES and NO. Comparing for NO is not an issue since NO == 0 == NO, but comparing for YES can be tricky, especially if you are relying on 3rd party code to play by the rules. Consider this:

1
2
3
4
5
6
7
BOOL b = 37;
if (b) {
    printf("b is YES!\n");
}
if (b != YES) {
    printf("b is not YES!\n");
}

The output from this would be as follows:

1
2
b is YES!
b is not YES!

The problem arises because direct comparison with YES will fail when the value of a BOOL type is a non-zero value other than 1.

Note that ObjC (assuming the default C99 setting is enabled) also supports the bool data type, which is an intrinsic boolean type and can only be set to true or false. A safe way to convert between BOOL and bool is as follows:

1
2
3
4
// from BOOL to bool
bool b = myBOOL ? true : false;
// and back
myBOOL = b ? YES : NO;

The moral of the story is to avoid direct comparisons between BOOL types and the YES constant.

  1. Great post, man. Concise and very useful. It’ll probably save me hours of frustrating debugging in the future.

  2. a question:
    in objective-c and iphone development,
    do both BOOL and bool allow setting with ! to toggle to the opposite?

    example:
    myBOOL = !myBOOL;
    newBOOL = !myBOOL;

    and so on.

    can i pass a message to a method with !myBOOL?

  3. That works fine. Basically the compiler is comparing to zero, which is why you can do stuff like:

    char* cp = some_address;
    if (cp) {
    // do something if cp != 0
    }

    if (!cp) {
    // do something if cp == 0
    }

    So, the magic is in the ! operator. Given:

    ! value

    the result is of type int and is the “logical negation” of the value:

    0 if value is nonzero;
    1 if value is 0.

    You can also say that the expression:

    ! value

    is equivalent to:

    (0 == value)

    Notice that this explicitly avoids comparing with YES (or 1), which was the main point of my original note.

    HTH!

  4. It is perfectly safe to use
    bool b = myBOOL;
    and
    myBOOL = b;

    These are exactly equivalent to your complicated question mark constructions. For example:

    bool b = 3.141592654;
    will set b to true. Conversion of anything to bool will set it to true if the original was not zero, and to false otherwise. No need to use “? true: false” because that’s what a conversion to bool does by definition.

    In the other direction, a bool will always be converted to 0 or 1, which corresponds to NO and YES in the BOOL type, so no worries there, either.

    An “if” condition is also implicitly converted to bool, so the same applies there.

    The only thing you should avoid, is explicitly comparing to YES.

  5. By the way, it is also perfectly safe to use “true” and “false” instead of the ugly upper case “YES” and “NO”. You won’t find a single YES or NO in my code, and it works just fine. Whenever setting a BOOL to true, the compiler automagically inserts a YES (implicit conversion of BOOL to bool). The resulting code is the same, maybe it will add a millisecond or so to my total compile time, and I guess a few bytes to the size of my code since YES and NO are shorter words, but otherwise it makes zero difference.

  6. Be very very careful with BOOLs. The worst scenario is not even mentioned in this thread. It is a common practice in C programing to use bitwise operators for checking conditions or states.

    Consider the following code:

    enum {
    kSomeConstant = 0x0100
    };

    BOOL test = ( 256 & kSomeConstant ) ;
    if ( test ) NSLog(@”BOOL passed”);
    if ( ( 256 & kSomeConstant ) ) NSLog(@”int passed”) ;

    Only the second NSLog will be executed !.

    This is because ‘test’ is actually a char type that can not hold the result of the operation, which is truncated to the least significant byte.

    So always, ever (did I say at all times?) use *only* results of boolean operators to assign to BOOLs.

    The solution for the code above is to change the test assignment by

    BOOL test = ( 256 & kSomeConstant ) != 0 ;

    Joan Lluch-Zorrilla.

  7. The safe way to compare booleans is:
    (a==0) == (b==0)
    or more compact:
    !a == !b

Comments are closed.