Book HomeActionScript: The Definitive GuideSearch this book

5.7. The Logical Operators

In Chapter 4, "Primitive Datatypes", we learned how to make logical decisions using Boolean values. The decisions we considered were based on single factors: if a movie hasn't loaded, don't start playing; if a spaceship has double-shot power, increase the damage its shots inflict, and so on. Not all programming logic is so simple. We'll often want to consider multiple factors in our branching (i.e., decision-making) logic.

Suppose, for example, that we are making a personalized Flash site that requires users to log in. If a user logs in as a guest, the content he can see is limited. When a registered user logs into the site, we set a variable that indicates, for the duration of our movie, that the user is allowed to see privileged content:

var userStatus = "registered";

To decide whether to allow access to a restricted area, we use a Boolean check like this:

if (userStatus == "registered") {
  // It's okay, let 'em in...
}

Suppose we want to demonstrate the site to prospective investors without forcing them to register and without showing them material reserved for registered users. We can invent a new user category, "specialGuest," that allows investors to see more than a guest but not as much as a registered user. When we want to identify someone as a special guest, we set userStatus to "specialGuest."

How do we perform a Boolean check now that there are two categories of users to allow in? We could do things the brutish, painful way by duplicating portions of our code:

if (userStatus == "registered") {
  // Execute legal-user code...
}

if (userStatus == "specialGuest") {
  // Execute exact same legal-user code...
}

Obviously, that's going to turn into a real headache to maintain. Every bit of complexity we add to our script doubles, and we end up with serious version-control problems.

We'd prefer to perform a single Boolean check that says, "If the user is registered or if the user is a special guest, then grant access." We can produce compound logical phrases like that with Boolean logical operators. Here, the logical OR operator (||) lets us check the status of multiple Boolean operations in a single expression:

if (userStatus == "registered" || userStatus == "specialGuest") {
  // Execute legal user code...
}

Nice, huh? Sometimes programming is so elegant. Such distinctive vertical lines . . . such supple parentheses . . .

5.7.1. Logical OR

The logical OR operator is most commonly used to initiate some action when at least one of two conditions is met. For example, "If I am hungry or I am thirsty, I'll go to the kitchen." The symbol for logical OR is made using two vertical line characters (||). The | character is typically accessible using the Shift key and the Backslash (\) key in the upper right of most keyboards, where it may be depicted as a dashed vertical line. Logical OR takes the general form:

operand1 || operand2

When both operands are Boolean expressions, logical OR returns true if either operand is true and returns false only if both operands are false. In summary:

true  || false   // true because first operand is true
false || true    // true because second operand is true
true  || true    // true (either operand being true is sufficient)
false || false   // false because both operands are false

The preceding is a simplified case in which both operands are Booleans, but the operands can be any valid expression including non-Boolean ones. In that case, the return value of a logical OR operation is not necessarily a Boolean (true or false). Technically, the first step in evaluating a logical OR is to convert operand1 to a Boolean; if the result of such a conversion is true, logical OR returns operand1's resolved value. Otherwise logical OR returns operand2's resolved value. Some code to demonstrate:

null || "hi there!"  // Operand1 does not convert to true, so the 
                     // operation returns operand2's value: "hi there!"

true || false        // Operand1 is true, so the operation returns
                     // operand1's value: true

"hey" || "dude"      // Operand1 is a nonempty string, so it converts to
                     // false and the operation returns
                     // operand2's value: "dude"

false || 5 + 5       // Operand1 does not convert to true so the
                     // value of operand2 (namely 10) is returned

In practice, we rarely make use of non-Boolean values returned by a logical OR expression. Instead, we normally use the result in a conditional statement where it is used to make a Boolean decision. Consider Example 5-3.

Example 5-3. A Logical OR Operation as a Conditional Test Expression

var x = 10;
var y = 15;
if (x || y) {
  trace("One of either x or y is not zero");
}

On line 3, we see a logical OR operation (x || y ) being used where a Boolean is expected as the test expression of an if statement. Our first step in determining the value of x || y is to convert 10 (the value of the first operand, x) to a Boolean. As Table 3-3 shows, any non-zero finite number converts to the Boolean true. When the first operand converts to true, the logical OR returns the value of the first operand, in this case 10. So to the interpreter, our if statement looks like this:

if (10) {
  trace("One of either x or y is not zero");
}

But 10 is a number, not a Boolean. So what happens? The if statement converts the return value of the logical OR operation to a Boolean. In this case, 10 is converted to the Boolean value true (again, according to the rules in Table 3-3), and the interpreter sees our code as:

if (true) {
  trace("One of either x or y is not zero");
}

And there you have it. The test expression is true, so the trace( ) statement between the curly braces is executed.

Note that if the first operand in a logical OR operation resolves to true, it is unnecessary and therefore inefficient to evaluate the second operand. Therefore, ActionScript evaluates the second operand only if the first operand resolves to false. This fact is useful in cases in which you don't want to resolve the second operand unless the first operand resolves to false. In this example, we check if a number is out of range. If the number is too small, there is no need to perform the second test in which we check whether it is too large:

if (xPos < 0 || xPos > 100) {
  trace ("xPos is not between 0 and 100 inclusive.");
}

5.7.2. Logical AND

Like the logical OR operator, logical AND is primarily used to execute a block of code conditionally, in this case only when both of two conditions are met. The logical AND operator takes the general form:

operand1 && operand2

Both operand1 and operand2 may be any valid expression. In the simplest case in which both operands are Boolean expressions, logical AND returns false if either operand is false and returns true only if both operands are true. In summary:

true  && false   // false because second operand is false
false && true    // false because first operand is false
true  && true    // true because both operands are true
false && false   // false because both operands are false (either is sufficient)

Let's see how the logical AND operator is used in two real examples. In Example 5-4, we execute a trace( ) statement only when two variables are both greater than 50.

Example 5-4. A Logical AND Operation as a Conditional Test Expression

x = 100;
y = 51;
if (x>50 && y>50) {
  trace("Both x and y are greater than 50");
}

Because the expressions x>50 and y>50 are both true, the trace( ) statement is executed.

In Example 5-5, we return to our web site example in which access was restricted to registered users and special guests. But this time we'll let users in only if the date is not January 1. Note the use of the Date object to determine the current date. Note that getMonth( ) returns to indicate January.

Example 5-5. Compound Logical Expressions

userStatus = "registered";
now = new Date( );        // Create a new Date object
day = now.getDate( );     // Returns an integer between 1 and 31
month = now.getMonth( );  // Returns an integer between 0 and 11

// Note the indentation style and parentheses...if statements may span
// multiple lines for the sake of readability
if ( ((userStatus == "registered") || (userStatus == "specialGuest")) 
    && (month + day) > 1) {
  // Let the user in...
}

The technical behavior of the logical AND operator is quite similar to that of the logical OR operator. First, operand1 is converted to a Boolean. If the result of that conversion is false, the value of operand1 is returned. If the result of that conversion is true, the value of operand2 is returned.

If the first operand in a logical AND operation resolves to false, it is unnecessary and therefore inefficient to evaluate the second operand. Therefore, ActionScript evaluates the second operand only if the first operand resolves to true. This fact is useful in cases in which you don't want to resolve the second operand unless the first operand resolves to true. In this example, we perform the division only if the divisor is nonzero:

if (numItems != 0 && total / numItems > 3) {
  trace ("You've averaged more than 3 dollars per transaction");
}

5.7.3. Logical NOT

The logical NOT operator (!) returns the Boolean opposite of its single operand. It takes the general form:

!operand

where operand may be any legal expression. If operand is true, logical NOT returns false. If operand is false, logical NOT returns true. If operand is not a Boolean, its value is converted to a Boolean for the sake of the operation and its opposite is returned.

Like the does-not-equal operator (!=), the logical NOT operator is convenient for testing what something isn't rather than what it is. Recall Example 5-5 in which we wanted to perform an action only if the date was not January 1. At first impression, this attempt might seem correct:

month != 0 && day != 1

We find, however, that month != 0 is true anytime the month is not January (so far so good), but day != 1 is actually false on the first day of every month. So the expression month != && day != 1 would exclude our users on the first day of any month, not just January 1. Hardly what we intended.

It's much easier to check if today is January 1:

month == 0 && day == 1

That expression yields true only on the first day of January. Once we've gotten that far, all we need is the NOT operator to determine when today is not January 1:

!(month==0 && day==1)

Obviously this code's intent is much clearer than the month+day > 1 test used in Example 5-5.

Another typical usage of the NOT operator is to toggle a variable from true to false and vice versa. For example, suppose you have a single button that is used to turn the sound on and off. You might use code like this:

soundState = !soundState  // Reverse the current sound state
if (soundState) {
  // If sound is turned on, make sure sounds are audible
} else {
  // If the sound is off, set the volume to 0 to mute it
}

Notice that ! is also used in the inequality operator (!=). As a programming token (i.e., symbol), the ! character usually means not, or opposite. It is unrelated to the ! symbol used to indicate "factorial" in common mathematic notation.

5.7.4. Logical Expressions and Data Values

Using logical operators to calculate a Boolean result is analogous to using arithmetic operators to calculate a numeric result. For example, the following four operands and three operators are used to calculate a single result:

userStatus == "registered" || userStatus == "specialGuest"

If the user is not registered, but is a special guest, the preceding expression reduces to:

false || true

which in turn reduces to the Boolean result true.

Here is an analogous arithmetic operation that reduces to a single number:

(1 + 2) * (3 + 4)  // Four values (1, 2, 3, 4) which become...
3 * 7              // two values (3, 7), which become...
21                 // a single value (21)

Remember, a complex expression that reduces to a Boolean can be used anywhere a single Boolean value is required (such as the test expression of a conditional statement).



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.