165

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?

Costique
  • 23,712
  • 4
  • 76
  • 79
Kevlar
  • 8,804
  • 9
  • 55
  • 81
  • 6
    From a practical standpoint there is no difference. You can probably do various tricks to demonstrate a difference, but you'd generally be straying into "undefined behavior" territory. – Hot Licks Jan 21 '12 at 19:03
  • On this topic, I recommend you checkout my interesting question: https://stackoverflow.com/q/65517700/5492956 You can see there is nuances of `YES` and `true`. – wzso Dec 31 '20 at 07:10

9 Answers9

106

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Dan J
  • 25,433
  • 17
  • 100
  • 173
  • 5
    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. – Hot Licks Jan 21 '12 at 19:01
  • 1
    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". – Lawrence Dol Feb 18 '14 at 18:15
  • Thanks Lawrence, I've made an update along those lines. – Dan J Mar 14 '14 at 17:12
  • Indeed, i didn't get the second output in Xcode 8.2. Where I fail? – Igor Kislyuk Feb 13 '17 at 15:49
  • 1
    @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. – Dmytro Mar 31 '18 at 21:34
  • 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. – Dmytro Mar 31 '18 at 21:38
85

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.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
57

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
Ky -
  • 30,724
  • 51
  • 192
  • 308
  • 3
    [[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. – DrFloyd5 Aug 09 '13 at 15:26
  • 4
    @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... – Ky - Mar 20 '15 at 13:19
  • 1
    @SamuelRenkert also the Linux backdoor that was found in 2003: `if (user_id = ROOT_UID)` – Ky - Dec 23 '15 at 16:52
15

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}
malex
  • 9,874
  • 3
  • 56
  • 77
14

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
Community
  • 1
  • 1
Barry Wark
  • 107,306
  • 24
  • 181
  • 206
1

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.

Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • This is essentially the same answer as DanJ's, from 2+ years earlier, with less detail. – Lawrence Dol Jul 09 '15 at 18:39
  • @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. – Grady Player Jul 09 '15 at 19:45
0

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];
Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Marco
  • 789
  • 1
  • 8
  • 13
  • 2
    I disagree; they both read the same, to me. However, in a UI for a lay person I think Yes/No looks nicer. – Lawrence Dol Jun 24 '11 at 01:23
  • 17
    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. – FreeAsInBeer Jul 21 '11 at 23:40
  • 1
    Half downvote for 2 imprecise answers and half downvote for [signing your answers](http://meta.stackexchange.com/a/3021/280621) – fpg1503 Mar 19 '15 at 19:10
-3

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');
})();
Dmytro
  • 5,068
  • 4
  • 39
  • 50
-7

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

Qix - MONICA WAS MISTREATED
  • 14,451
  • 16
  • 82
  • 145
Marco
  • 789
  • 1
  • 8
  • 13