A deeper than necessary dive into the exact expression evaluation behavior of the basic "Watch Expression" in VBA.
This is the first in a series of articles that will dive into the behavior of the different Watch Types in VBA:
- Watch Expression
- Break When Value Is True
- Break When Value Changes
We'll focus on the first type in this article: Watch Expression. This most basic type of Watch will not force your code to halt the way the other two types can. This has important implications when it comes to debugging performance.
To demonstrate the behavior of the different Watch Types, I'm going to use my own custom Watch() method to illustrate just how often these expressions are being evaluated.
Here's the sample code I will be using for the demonstration:
#If VBA7 Then Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) #Else Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) #End If Dim MyVar As Integer Function Watch(Val, Optional CalledFrom As String = "") Debug.Print Val, CalledFrom Sleep 1000 'Sleep for one second for demo purposes Watch = Val End Function Sub TestWatch() MyVar = 0 Debug.Print "Alpha" Debug.Print "Bravo" MyVar = 2 Debug.Print "Charlie" End Sub
Here's the expression I will be watching. Note that each time this expression is evaluated, the value of MyVar will be printed to the immediate window, along with the current date and time.
Watch(MyVar, Now) = 2
Throughout this series of articles, the code itself and the expression being watched will remain the same. The only things I will be changing are:
- the Watch Type
- the setting of breakpoints
- method of code execution (e.g., [F5] "Run" vs. [F8] "Step Into")
Watch Type: • Watch Expression
Run Sub [F5] - No Breakpoints
In the first test, we're just running the test function using Run > Run Macro (F5):
Run Sub [F5] - Breakpoints as indicated
In this next test, I've added a couple of breakpoints on the lines where I'm setting the value of MyVar. Here's the result:
Notice that the expression is evaluated when the code halts, not when it starts. That's why at the first breakpoint, the value of MyVar is 2 (it's left over from the previous run). Then, at the second breakpoint, the value of MyVar is 0 (as set earlier in the function).
Step Into [F8]
For the final test, I'm showing what happens when we step through the TestWatch() function one line at a time.
- This is the starting point; I have not pressed F8 yet.
- The first F8 press sets the next statement to the routine declaration line. The value of MyVar is 2 from the previous run. No lines of code have actually executed yet. However, the Watch expression has been evaluated.
- The second F8 press executes the routine declaration line. Note that the value of MyVar is still 2 because the
MyVar = 0line has not yet been executed.
- The third F8 press executes the line that sets MyVar to zero. Note that the value of MyVar is now 0 in the immediate window.
- The fourth F8 press prints "Alpha" to the immediate window. And then the Watch Expression is evaluated.
- The fifth F8 press prints "Bravo" to the immediate window.
- The sixth F8 press sets the value of MyVar to 2.
- The seventh F8 press prints "Charlie" to the immediate window.
- The eighth F8 press executes the End Sub line and exits the routine. After exiting the routine, the watched expression is evaluated one last time.