Short-Circuiting Logical Expressions: A Timing Example
As an example, consider the problem of short-circuiting logical expressions. Assume the following code:
If i <= 20 And i >= 10 Then i = i + 1
Looking at this logically, you can see that if i is greater than 20, it’s pointless to check whether it’s also less than 10. Some compilers and interpreters know this and skip the second condition (short-circuiting is the technical term) if the first condition settles the matter. But is Visual Basic among them? Consider an alternative but equivalent statement:
If i <= 20 Then If i >= 10 Then i = i + 1
In this case, I’m not trusting Visual Basic to optimize. I tell it to always check the first condition and to check the second only if the first is true. If Visual Basic can optimize the first example, these two pieces of code should run at about the same speed. There’s only one way to find out:
Function LogicalAndVsNestedIf(cIter As Long) As String
Dim sec As Currency, secOut As Currency
Dim sMsg As String, i As Integer, iIter As Long
i = 21
ProfileStart sec
For iIter = 1 To cIter
If i <= 20 And i >= 10 Then i = i + 1
Next
ProfileStop sec, secOut
sMsg = sMsg & “If a And b Then: “ & secOut & “ sec” & sCrLf
i = 21
ProfileStart sec
For iIter = 1 To cIter
If i <= 20 Then If i >= 10 Then i = i + 1
Next
ProfileStop sec, secOut
sMsg = sMsg & “If a Then If b Then: “ & secOut & “ sec” & sCrLf
LogicalAndVsNestedIf = sMsg
End Function
The results will vary, depending on the computer and operating system used, on what other programs are running at the same time, whether the code is compiled or not, and on whether the moon is full. I ran all the timing tests in this book on a 90-MHz Pentium-based computer running Windows 95. The “Performance” sidebar on page 34 indicates the results. Although the timings are significantly different for native code versus p-code, you can reach a reasonable conclusion: no short-circuit.
Just so you don’t think that Visual Basic is unsophisticated and unnecessarily inefficient, it has its reasons. In Visual Basic, the And and Or operators double as logical operators and bitwise operators. You would have a different situation with the following line:
If a Or b Or c = &HEACC Then Exit Sub
In this case, you’re combining the bits of a, b, and c and then testing to see whether the result has a specific value. A short-circuit would be inappropriate. But for Basic to know that, it would need to look at the entire expression and make some assumptions (possibly erroneous) about your intentions. For example, Basic could assume that an expression with an equal sign is always bitwise but that an expression without an equal sign is always logical. That’s an iffy assumption, and Visual Basic doesn’t make it.
WARNING Visual Basic’s failure to short-circuit logical expressions can
cause problems other than poor performance. Consider the
following expression:
If (iStart > 1) And Mid$(s, iStart - 1, 1) = “ “ Then
The first condition attempts to protect against an illegal condition in the second. If iStart is 1, the second argument of Mid$ is 0, which causes an illegal function call. You might hope that since the first condition is false, the second illegal statement won’t be executed and you won’t get that obnoxious error. Wrong!
Problem: Does Visual Basic short-circuit logical expressions? Or does a logical And operation take the same time as an equivalent nested If/Then?
Problem |
Native Code |
P-Code |
If a And b Then |
.0215 sec |
.5307sec |
If a Then If b Then |
.0220 sec |
.3518 sec |
Conclusion: This is the first of many timing notes. Don’t take the numbers too seriously; they’re for rough comparison only. For real results, run the Time It program yourself on machines like the ones you expect your customers to use. In this case, however, the difference in p-code is dramatic enough to justify a conclusion: Visual Basic does not short-circuit logical expressions. But you can also see that for compiled code there is virtually no difference. The numbers above actually show an insignificant edge for the logical expression. But remember, this result is for a very trivial example in my TimeIt test. You wouldn’t get the same result if the right side of the expression were actually an expensive function call.