Previous section   Next section

3.10 Logical Operators Within Conditionals

If statements test whether a condition is true. Often you will want to test whether two conditions are both true, or only one is True, or neither is True. VB.NET provides a set of logical operators for this, as shown in Table 3-3. This table assumes two variables, x and y, in which x has the value 5, and y the value 7.

Table 3-3. Logical operators (assumes x = 5 and y = 7)

Operator

Given this statement:

The expressionevaluates to:

Logic

And

x = 3 And y = 7

False

Both must be true to evaluate true.

Or

x = 3 Or y = 7

True

Either or both must be true to evaluate true.

XOr

X = 5 XOr y = 7

False

True only if one (and only one) statement is true.

Not

Not x = 3

True

Expression must be false to evaluate true.

The And operator tests whether two statements are both true. The first line in Table 3-3 includes an example that illustrates the use of the And operator:

x = 3 And y = 7

The entire expression evaluates false because one side (x = 3) is false. (Remember that x = 5 and y = 7.)

With the Or operator, either or both sides must be true; the expression is false only if both sides are false. So, in the case of the example in Table 3-3:

x = 3 Or y = 7

the entire expression evaluates true because one side (y = 7) is true.

The XOr logical operator (which stands for eXclusive Or) is used to test if one (and only one) of the two statements is correct. Thus, the example from Table 3-3:

x = 5 XOr y = 7

evaluates false because both statements are true. (The XOr statement is false if both statements are true, or if both statements are false; it is true only if one, and only one, statement is true.)

With the Not operator, the statement is true if the expression is false, and vice versa. So, in the accompanying example:

Not x = 3

the entire expression is true because the tested expression (x = 3) is false. (The logic is: "It is true that it is not true that x is equal to 3.")

All of these examples appear in context in Example 3-26.

Example 3-26. The logical operators
Option Strict On
Imports System
Module Module1

   Sub Main( )

      Dim x As Integer = 5
      Dim y As Integer = 7

      Dim andValue As Boolean
      Dim orValue As Boolean
      Dim xorValue As Boolean
      Dim notValue As Boolean

      andValue = x = 3 And y = 7
      orValue = x = 3 Or y = 7
      xorValue = x = 3 Xor y = 7
      notValue = Not x = 3

      Console.WriteLine("x = 3 And y = 7. {0}", andValue)
      Console.WriteLine("x = 3 Or y = 7. {0}", orValue)
      Console.WriteLine("x = 3 Xor y = 7. {0}", xorValue)
      Console.WriteLine("Not x = 3. {0}", notValue)

   End Sub 'Main 

End Module

Output:
x = 3 And y = 7. False
x = 3 Or y = 7. True
x = 3 Xor y = 7. True
Not x = 3. True

3.10.1 Short-Circuit Evaluation

Consider the following code snippet:

Dim x As Integer = 7
If (x < 8) Or (x > 12) Then

The If statement here is a bit complicated. Everything in the If statement must evaluate true for the If statement to be true. Within the If statement are two expressions (x < 8) and (x > 12) separated by the keyword Or. It turns out that x is less than 8, so it does not matter whether or not x is greater than 12, and there is no logical reason for the compiler to evaluate the second term (i.e., after the Or).

As it stands, however, the second term will be evaluated. You can instruct the compiler not to evaluate the second term if the first term is true, by changing the Or keyword to OrElse:

If (x < 8) OrElse (x > 12) Then

You can prove to yourself that the evaluation was short-circuited by moving the comparisons (less than and greater than) to methods, as shown in Example 3-27.

Example 3-27. Short-circuit evaluation using OrElse
Option Strict On
Imports System
Module Module1

    Function IsBigger( _
    ByVal firstVal As Integer, _
    ByVal secondVal As Integer) _
        As Boolean

        If firstVal > secondVal Then
            Return True
        Else
            Return False
        End If

    End Function

    Function IsSmaller( _
    ByVal firstVal As Integer, _
    ByVal secondVal As Integer) _
        As Boolean

        If firstVal < secondVal Then
            Return True
        Else
            Return False
        End If

    End Function

    Sub Main( )

        Dim x As Integer = 7
        If IsSmaller(x, 8) OrElse IsBigger(x, 12) Then
            Console.WriteLine("x < 8 OrElse x > 12")
        Else
            Console.WriteLine("Not True that x < 8 OrElse x > 12")
        End If

    End Sub 'Main

End Module

In Example 3-27 you create two methods, IsBigger and IsSmaller. Each takes two parameters. IsBigger returns true if the first parameter is larger than the second, IsSmaller returns true if the first parameter is smaller than the second.

If you write Example 3-27 in Visual Studio .NET and then put a break point on the If statement in Main( ), you can see the evaluation of the two sides of the OrElse statement. The compiler will step into IsBigger, but will never step into IsSmaller. Since IsBigger returned true, IsSmaller need not be called.

Change the value of x to 15 and you will find that both IsBigger and IsSmaller are invoked. Since IsBigger returns false, the compiler must test IsSmaller to see if it might return true.

You can accomplish short-circuit evaluation for the And keyword by using the keyword AndAlso. If you leave x set to 15, but change the If statement in Main( ) to the following:

If IsSmaller(x, 8) AndAlso IsBigger(x, 12) Then

you will see the compiler step into IsSmaller but never step into IsBigger. Since the IsSmaller method returns false, there is no need to test IsBigger. AndAlso requires that both parts of the statement evaluate true. Once you have the first side evaluate false, there is no need to test the second side.

3.10.2 Operator Precedence

The compiler must know the order in which to evaluate a series of operators. For example, if you write:

myVariable = 5 + 7 * 3

there are three operators for the compiler to evaluate (=, +, and *).

The compiler could evaluate this equation from left to right, which would:

  1. Assign the value 5 to myVariable.

  2. Add 7 to the 5, resulting in 12.

  3. Multiply the result (12) by 3, giving a final answer of 36.

However, because the assignment is done in step 1, the final value of 36 would then be thrown away. This is clearly not what is intended.

The rules of precedence tell the compiler which operators to evaluate first. As is the case in algebra, multiplication has higher precedence than addition, so 5 + 7 * 3 is equal to 26 rather than 36. Both addition and multiplication have higher precedence than assignment, so the compiler will do the math, and then assign the result (26) to myVariable only after the math is completed. In VB.NET, parentheses are used to change the order of precedence much as they are in algebra. Thus, you can change the result by writing:

myVariable = (5+7) * 3

Grouping the elements of the assignment in this way causes the compiler to add 5+7, multiply the result by 3, and then assign that value (36) to myVariable.

Within a single line of code, operators are evaluated in the following order:

Relational operators are evaluated left to right. Mathematical operators are evaluated in this order:

The logical operators are evaluated in this order:

In some complex equations, you might need to nest parentheses to ensure the proper order of operations. For example, assume I want to know how many seconds my family wastes each morning. It turns out that the adults spend 20 minutes over coffee each morning and 10 minutes reading the newspaper. The children waste 30 minutes dawdling and 10 minutes arguing.

Here's my algorithm:

(((minDrinkingCoffee + minReadingNewspaper) * numAdults) + 
((minDawdling + minArguing) * numChildren)) * secondsPerMinute

Although this works, it is hard to read and hard to get right. It's much easier to use interim variables:

wastedByEachAdult = minDrinkingCoffee +  minReadingNewspaper
wastedByAllAdults = wastedByEachAdult * numAdults
wastedByEachKid = minDawdling  + minArguing
wastedByAllKids = wastedByEachKid * numChildren
wastedByFamily = wastedByAllAdults + wastedByAllKids
totalSeconds = wastedByFamily * 60

The latter example uses many more interim variables, but it is far easier to read, understand, and (most important) debug. As you step through this program in your debugger, you can see the interim values and make sure they are correct.

A more complete listing is shown in Example 3-28.

Example 3-28. Using parentheses and interim variables
Option Strict On
Imports System
Module Module1

   Sub Main( )
      Dim minDrinkingCoffee As Integer = 5
      Dim minReadingNewspaper As Integer = 10
      Dim minArguing As Integer = 15
      Dim minDawdling As Integer = 20

      Dim numAdults As Integer = 2
      Dim numChildren As Integer = 2

      Dim wastedByEachAdult As Integer
      Dim wastedByAllAdults As Integer
      Dim wastedByEachKid As Integer
      Dim wastedByAllKids As Integer
      Dim wastedByFamily As Integer
      Dim totalSeconds As Integer

      wastedByEachAdult = minDrinkingCoffee + minReadingNewspaper
      wastedByAllAdults = wastedByEachAdult * numAdults
      wastedByEachKid = minDawdling + minArguing
      wastedByAllKids = wastedByEachKid * numChildren
      wastedByFamily = wastedByAllAdults + wastedByAllKids
      totalSeconds = wastedByFamily * 60

      Console.WriteLine("Each adult wastes {0} minutes", wastedByEachAdult)
      Console.WriteLine("Each child wastes {0} mintues", wastedByEachKid)
      Console.WriteLine("Total minutes wasted by entire family: {0}", _
               wastedByFamily)
      Console.WriteLine("Total wasted seconds: {0}", totalSeconds)


   End Sub ' End of Main( ) module definition 

End Module
Output:
Each adult wastes 15 minutes
Each child wasts 35 mintues
Total minutes wasted by entire family: 100
Total wasted
 seconds: 6000





  Previous section   Next section
Top