Boolean data types are intended to symbolize binary values, usually denoted by 1
and 0
, true
and false
, or even YES
and NO
. Boolean types are used to represent truth logic, which is based on Boolean algebra. This is just a way of saying that Boolean values are used in conditional statements, such as if
or while
, to evaluate logic or repeat an execution conditionally.
Equality operations include any operations that compare the value of any two entities. The equality operators are:
==
implies equal to!=
implies not equal to
Relational operations include any operations that test a relation between two entities. The relational operators are:
>
implies greater than>=
implies greater than or equal to<
implies less than<=
implies less than or equal to
Logic operations include any operations in your program that evaluate and manipulate Boolean values. There are three primary logic operators, namely AND
, OR
, and NOT
. Another, slightly less commonly used operator, is the exclusive or, or XOR operator. All Boolean functions and statements can be built with these four basic operators.
The AND operator is the most exclusive comparator. Given two Boolean variables A and B, AND will return true
if, and only if, both A and B is true
. Boolean variables are often visualized using tools called truth tables. Consider the following truth table for the AND operator:
A |
B |
A ^ B |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
1 |
This table demonstrates the AND operator. When evaluating a conditional statement, 0 is considered to be false
, while any other value is considered to be true
. Only when the value of both A and B is true
, is the resulting comparison of A ^ B also true
.
The OR operator is the inclusive operator. Given two Boolean variables A and B, OR will return true
if either A or B is true
, including the case when both A and B are true
. Consider the following truth table for the OR operator:
A |
B |
A v B |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
Next, the NOT A operator is true
when A is false
, and false
when A is true
. Consider the following truth table for the NOT operator:
A |
!A |
0 |
1 |
1 |
0 |
Finally, the XOR operator is true
when either A or B is true
, but not both. Another way to say it is, XOR is true
when A and B are different. There are many occasions where it is useful to evaluate an expression in this manner, so most computer architectures include it. Consider the following truth table for XOR:
A |
B |
A XOR B |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
Just as with arithmetic, comparison and Boolean operations have operator precedence. This means the architecture will give a higher precedence to one operator over another. Generally speaking, the Boolean order of operations for all languages is as follows:
Parentheses
Relational operators
Equality operators
Bitwise operators (not discussed)
NOT
AND
OR
XOR
Ternary operator
Assignment operators
It is extremely important to understand operator precedence when working with Boolean values, because mistaking how the architecture will evaluate complex logical operations will introduce bugs in your code that you will not understand how to sort out. When in doubt, remember that, as in arithmetic parentheses, take the highest precedence and anything defined within them will be evaluated first.
As you recall, AND only returns true
when both of the operands are true
, and OR returns true
as soon as one operand is true
. These characteristics sometimes make it possible to determine the outcome of an expression by evaluating only one of the operands. When your applications stops evaluation immediately upon determining the overall outcome of an expression, it is called short-circuiting. There are three main reasons why you would want to use short-circuiting in your code.
First, short-circuiting can improve your application's performance by limiting the number of operations your code must perform. Second, when later operands could potentially generate errors based on the value of a previous operand, short-circuiting can halt execution before the higher risk operand is reached. Finally, short-circuiting can improve the readability and complexity of your code by eliminating the need for nested logical statements.
C#
C# uses the bool
keyword as an alias of System.Boolean
and stores the values true
and false
:
//C# bool a = true; bool b = false; bool c = a; Console.WriteLine("a: {0}", a); Console.WriteLine("b: {0}", b); Console.WriteLine("c: {0}", c); Console.WriteLine("a AND b: {0}", a && b); Console.WriteLine("a OR b: {0}", a || b); Console.WriteLine("NOT a: {0}", !a); Console.WriteLine("NOT b: {0}", !b); Console.WriteLine("a XOR b: {0}", a ^ b); Console.WriteLine("(c OR b) AND a: {0}", (c || b) && a); /* Output a: True b: False c: True a AND b: False a OR b: True NOT a: False NOT b: True a XOR b: True (c OR b) AND a: True */
Java
Java uses the boolean
keyword for the primitive Boolean data type. Java also provides a Boolean
wrapper class for the same primitive type:
//Java boolean a = true; boolean b = false; boolean c = a; System.out.println("a: " + a); System.out.println("b: " + b); System.out.println("c: " + c); System.out.println("a AND b: " + (a && b)); System.out.println("a OR b: " + (a || b)); System.out.println("NOT a: " + !a); System.out.println("NOT b: " + !b); System.out.println("a XOR b: " + (a ^ b)); System.out.println("(c OR b) AND a: " + ((c || b) && a)); /* Output a: true b: false c: true a AND b: false a OR b: true NOT a: false NOT b: true a XOR b: true (c OR b) AND a: true */
Objective-C
Objective-C uses the BOOL
identifier to represent Boolean values:
//Objective-C BOOL a = YES; BOOL b = NO; BOOL c = a; NSLog(@"a: %hhd", a); NSLog(@"b: %hhd", b); NSLog(@"c: %hhd", c); NSLog(@"a AND b: %d", a && b); NSLog(@"a OR b: %d", a || b); NSLog(@"NOT a: %d", !a); NSLog(@"NOT b: %d", !b); NSLog(@"a XOR b: %d", a ^ b); NSLog(@"(c OR b) AND a: %d", (c || b) && a); /* Output a: 1 b: 0 c: 1 a AND b: 0 a OR b: 1 NOT a: 0 NOT b: 1 a XOR b: 1 (c OR b) AND a: 1 */
Note
As it happens, Boolean data types give Objective-C yet another opportunity to prove it is more complex than its counterparts. The language does not provide one identifier or class to represent logic values. It provides five. For the sake of simplicity (and because my editor won't give me the extra pages), we're only going to use BOOL
in this text. If you want to know more, I encourage you to check out the Additional resources section at the end of this chapter.
Swift
Swift uses the Bool
keyword for the primitive Boolean data type:
//Swift var a : Bool = true var b : Bool = false var c = a print("a: \(a)") print("b: \(b)") print("c: \(c)") print("a AND b: \(a && b)") print("a OR b: \(a || b)") print("NOT a: \(!a)") print("NOT b: \(!b)") print("a XOR b: \(a != b)") print("(c OR b) AND a: \((c || b) && a)") /* Output a: true b: false c: true a AND b: false a OR b: true NOT a: false NOT b: true a XOR b: true (c OR b) AND a: true */
In the preceding example, the Boolean object c
is not explicitly declared as Bool
, but it is implicitly typed as a Bool
. In Swift terms, the data type has been inferred in this case. Also, note that Swift does not provide a specific XOR operator, so if you need that comparison, you should use the (a != b)
pattern.
Tip
Objective-C nil values
In Objective-C, the value nil
also evaluates to false
. Although other languages must handle NULL objects with care, Objective-C will not crash when it attempts to perform an operation on a nil object. Speaking from personal experience, this can be somewhat confusing for developers who learned C# or Java before learning Objective-C, and thus expect an unhandled NULL object to crash their app. However, it is common for Objective-C developers to use this behavior to their advantage. Many times, simply checking whether an object is nil
logically confirms whether an operation was successful, saving you from writing tedious logical comparisons.