By Kevlar


2009-03-05 17:09:55 8 Comments

Simple question really; is there a difference between these values (and is there a difference between BOOL and bool)? A co-worker mentioned that they evaluate to different things in Objective-C, but when I looked at the typedefs in their respective .h files, YES/TRUE/true were all defined as 1 and NO/FALSE/false were all defined as 0. Is there really any difference?

9 comments

@malex 2016-05-14 12:41:56

The main (dangerous!) difference between true and YESis in JSON serialization.

For example, we have JSON-type server request and need to send true/false in json sence:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

Then we convert it to JSON string before sending as

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

The result is

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

Due to API logic jsonString1 could result in an error.

So be careful with booleans in Objective-C.

To sum up, only exact @YES and casted value as @((BOOL)expression) are of __NSCFBoolean type and converted to true with JSON serialization. Any other expressions like @(expression1 && expression2) (even @(YES && YES)) are of __NSCFNumber (int) type and converted to 1 in JSON.

P.S. You can simply use string-valued boolean

@{@"bool" : @"true"}; // in JSON {"bool":true}

@Dmitry 2018-03-31 21:24:09

First let's examine what true and false is and what gives them meaning in the first place.

we can construct a structure called if a then b else c in lambda calculus as follows:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

In JavaScript, This looks like this:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

in order for ifThenElse to be useful, we need a function "true" that chooses either right or left, and does that while ignoring the other option, or a function "false" that chooses the option "true" doesn't take.

We can define these functions as follows:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

in JavaScript it looks like this:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

now we can do the following

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

with doThis and doThat being (\a. ()) because lambda calculus does not offer any services such as printing/math/strings, all we can do is do nothing and say we did it(and later cheat by replacing it with services in our system that provide side effects we want)

so let's see this in action.

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

That's a deep environment that could be simplified if we were allowed to use arrays/maps/arguments/or more than one statement to split into multiple functions, but i want to keep is as pure as I can limiting myself to functions of exactly one argument only.

notice that the name True/False has no inherent significance, we can easily rename them to yes/no, left/right, right/left, zero/one, apple/orange. It has significance in that whatever choice is made, it is only caused by the kind of chooser made it. So if "LEFT" is printed, we know that the chooser could only be true, and based on this knowledge we can guide our further decisions.

So to summarize

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();

@Dan J 2011-03-29 12:45:52

I believe there is a difference between bool and BOOL, check out this webpage for an explanation of why:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Because BOOL is an unsigned char rather than a primitive type, variables of type BOOL can contain values other than YES and NO.

Consider this code:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

The output is:

b is not NO!
b is not YES!

For most people this is an unnecessary concern, but if you really want a boolean it is better to use a bool. I should add: the iOS SDK generally uses BOOL on its interface definitions, so that is an argument to stick with BOOL.

@Hot Licks 2012-01-21 19:01:43

But note that the original C implementation had no bool, and hence it's been the tradition to use an int or char as a Boolean, sometimes with a #define to hide the difference and sometimes not. In fact, I'm not sure if even current standards require bool to be implemented in a way that prevents examining it's internal structure.

@Lawrence Dol 2014-02-18 18:15:39

Although, the first printf tells lies. The value of b is not YES, it's "not zero", which is what the condition tests. So you should have printf("b is not zero"), which is not necessarily the same as YES. In this case, b is both "not zero" and "not YES".

@Dan J 2014-03-14 17:12:42

Thanks Lawrence, I've made an update along those lines.

@Igor Kislyuk 2017-02-13 15:49:55

Indeed, i didn't get the second output in Xcode 8.2. Where I fail?

@Dmitry 2018-03-31 21:34:37

@HotLicks there's no inherent difference between 0, not zero and false and true. As long as the value is intended to be a logical boolean, it will always have this interface in order to preserve binary compatibility. The problems begin when you use non booleans that seem like booleans, for example c standard library application entry function, main returns 0 on success, many end up thinking of this 0 as a boolean, when in fact it's an application defined enumeration or user defined value, which callees often expect to be nonzero on abnormal termination.

@Dmitry 2018-03-31 21:38:03

ps: magic numbers are no more meaningful than macros that represent them. In many cases macros and constants are LESS meaningful than the magic numbers, for example, you're more likely to find the meaning of the boot signature 0xaa55 on google than MYSIG, which makes reading source code for bootloaders often less intuitive than without the macros. True and False are less meaningful than int in that we can't deterministically know their size, because while int is always 16 or 32 bits, bool might through some heresy be 1 byte or 8 bytes.

@Grady Player 2014-10-23 03:51:48

There is a subtle bug that no one has mentioned here, that I thought I would include... more of a logical error than anything:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

so the issue here is just that (YES==1) and in C the comparison isn't a boolean one, but one based on value.

because YES is just a #define (rather than something intrinsic to the language), it has to be some value, and 1 makes the most sense.

@Lawrence Dol 2015-07-09 18:39:42

This is essentially the same answer as DanJ's, from 2+ years earlier, with less detail.

@Grady Player 2015-07-09 19:45:20

@LawrenceDol I don't know, it mentions that YES is only #defined to be 1 and not intrinsic to the language, like it might be in a higher level language... someone could possibly get value from that... but good trolling, with ya.

@Marco 2009-03-05 17:12:08

No, YES/NO is a different way to refer to TRUE/FALSE(1/0)

@Marco 2009-03-05 17:29:25

I think they add YES/NO to be more self-explanatory in many cases. For example:

[button setHidden:YES];

sounds better than

[button setHidden:TRUE];

@Lawrence Dol 2011-06-24 01:23:05

I disagree; they both read the same, to me. However, in a UI for a lay person I think Yes/No looks nicer.

@FreeAsInBeer 2011-07-21 23:40:45

I disagree as well. If anything, it reads poorly due to not sticking to the unwritten standards that have been used for years in other languages. IE is a prime example of what happens when you fail to adhere to a great number of standards.

@Supuhstar 2013-02-20 01:36:49

-1 for leaving two answers that could be listed as one

@fpg1503 2015-03-19 19:10:29

Half downvote for 2 imprecise answers and half downvote for signing your answers

@Supuhstar 2013-02-20 01:35:14

I did an exhaustive test on this. My results should speak for themselves:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

The output is:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0

@DrFloyd5 2013-08-09 15:26:48

[[NSObject]alloc]init] does not equal TRUE or YES. So testing for object initialization with if ([[NSObject]alloc]init]==TRUE) will fail. I've never been comfortable with a Language defining a singular "true" value when in fact any non zero value will do.

@Supuhstar 2015-03-20 13:19:00

@SamuelRenkert I've never been comfortable with a language taking a non-Boolean value in an if or a while. Like... while("guitar gently weeps") shouldn't work...

@Supuhstar 2015-12-23 16:52:17

@SamuelRenkert also the Linux backdoor that was found in 2003: if (user_id = ROOT_UID)

@Lawrence Dol 2009-03-05 17:22:41

There is no practical difference provided you use BOOL variables as booleans. C processes boolean expressions based on whether they evaluate to 0 or not 0. So:

if(someVar ) { ... }
if(!someVar) { ... }

means the same as

if(someVar!=0) { ... }
if(someVar==0) { ... }

which is why you can evaluate any primitive type or expression as a boolean test (including, e.g. pointers). Note that you should do the former, not the latter.

Note that there is a difference if you assign obtuse values to a so-called BOOL variable and test for specific values, so always use them as booleans and only assign them from their #define values.

Importantly, never test booleans using a character comparison -- it's not only risky because someVar could be assigned a non-zero value which is not YES, but, in my opinion more importantly, it fails to express the intent correctly:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

In other words, use constructs as they are intended and documented to be used and you'll spare yourself from a world of hurt in C.

@Barry Wark 2009-03-05 17:57:23

You might want to read the answers to this question. In summary, in Objective-C (from the definition in objc.h):

typedef signed char        BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED


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

Related Questions

Sponsored Content

26 Answered Questions

[SOLVED] What's the difference between the atomic and nonatomic attributes?

25 Answered Questions

[SOLVED] How do I sort an NSMutableArray with custom objects in it?

13 Answered Questions

[SOLVED] What is a typedef enum in Objective-C?

42 Answered Questions

[SOLVED] Passing Data between View Controllers

2 Answered Questions

2 Answered Questions

[SOLVED] Objective-C TRUE/FALSE vs true/false

14 Answered Questions

[SOLVED] Constants in Objective-C

30 Answered Questions

[SOLVED] Shortcuts in Objective-C to concatenate NSStrings

22 Answered Questions

[SOLVED] Has TRUE always had a non-zero value?

4 Answered Questions

Sponsored Content