When you declare a variable within a procedure, only code within that procedure can read or change the value of that variable: Its scope is local to that procedure. Sometimes, however, you want to use a variable with a broader scope, one whose value is available to all procedures within the same module, or even to all the procedures in all modules. With Visual Basic, you can specify the scope of a variable when you declare it.
Depending on how you declare a variable, it’s either a procedure-level or a module-level variable.
Scope | Private | Public |
Procedure-level | Variables are private to the procedure in which they appear. | Not applicable. You can’t declare public variables within a procedure. |
Module-level | Variables are private to the module in which they appear. | Variables are available to all modules. |
Procedure-level variables are recognized only in the procedure in which they’re declared. These are also known as local variables. You declare them with the Dim or Static keywords, as follows:
Dim intTemp As Integer
Static intPermanent As Integer
Local variables declared with the Dim keyword exist only as long as the procedure is running. Local variables declared with the Static keyword exist the entire time your application is running.
Because of the advantages they provide, consider using local variables for any kind of temporary calculation. For example, you can create a dozen different procedures containing a variable called intTemp
. As long as each intTemp
is declared as a local variable, each procedure recognizes only its own version of intTemp
. Any one procedure can alter the value in its local intTemp
without affecting intTemp
variables in other procedures.
Note Implicitly declared variables always have a local scope.
See Also For more information on procedures, see Chapter 2, “Introducing Visual Basic.”
By default, a module-level variable is available to all the procedures in that module, but not to code in other modules. You create module-level variables in form, report, and standard modules by declaring them with the Dim or Private keywords in the Declarations section at the top of the module. For example, use either of the following statements:
Dim intTemp As Integer
Private intTemp As Integer
At the module level, there is no difference between Private and Dim. However, using Private is recommended because it readily contrasts with Public and makes your code easier to read.
See Also For more information on modules, see Chapter 2, “Introducing Visual Basic.”
To make a module-level variable available to other modules, use the Public keyword to declare the variable. (The Public statement has replaced the Global statement used for declaring variables in Microsoft Access version 2.0.) The values in public variables are available to all procedures in all modules in your application. Like all module-level variables, public variables are declared in the Declarations section at the top of the module, as shown in the following example:
Public intX As Integer
Note You can’t declare public variables within a procedure.
In a form, report, or standard module, if you want to refer to a public variable in a different form or report module, you must qualify the reference by using the name of the form or report, such as Forms!Orders.intX
.
See Also For more information on form and report modules, see Chapter 2, “Introducing Visual Basic.”
You can declare public variables in any module. Generally speaking, each public variable should be located in the module of which it’s a logical member. However, if you have public variables that are used for purely global purposes and are not specifically related to a particular module, you can put them all in one module. This makes the variables easier to find and your code easier to read.
A variable can’t change scope while your code is running. However, you can use the same name for different variables under certain conditions.
If public variables in different modules share the same name, it’s possible to differentiate between them in code. For example, if a public Integer variable intX
is declared in both of the standard modules Module1 and Module2, you can refer to them as Module1.intX
and Module2.intX
to get the correct values.
You can also have a variable with the same name at a different scope. For example, you could have a public variable named intX
and then, within a procedure, declare a local variable named intX
. References to the name intX
within the procedure would access the local variable, while references to intX
outside the procedure would access the public variable. The module-level variable can be accessed from within the procedure by qualifying the variable with the module name.
' This code is in the form module for Form1. Within the Test Sub
' procedure, the name intX always refers to the local variable, not
' to the variable declared in the Public statement at the top.
Public intX As Integer
Sub Test()
Dim intX As Integer
intX = 2 ' intX has a value of 2 (even though
MsgBox Forms!Form1.intX ' MsgBox shows the value of intX in
End Sub ' Form1, which is 1).
Private Sub Form_Load()
intX = 1
End Sub
Private Sub Command1_Click()
Test ' intX has a value of 2.
End Sub
In general, when variables have the same name but a different scope, the more local variable shadows (is accessed in preference to) less local variables. So, if you also had a private module-level variable named intX
, it would shadow the public variable intX
within that module (and the local intX
would shadow the private module-level intX
within that procedure).
Shadowing rules treat form and report properties and controls, user-defined types, constants, and procedures as module-level variables in the form or report module. Thus, all module-level shadowing rules apply to each of these. You can’t have a form or report property or control with the same name as a module-level variable, constant, user-defined type, or procedure because both are in the same scope.
Within the form or report module, local variables with the same names as controls on the form or report shadow the controls. You need to either qualify the control with a reference to the form or report, or you need to use the Me keyword to set or get its value or any of its properties. The following code shows one way to do this:
Private Sub Form_Click()
Dim Text1, Caption
' Assume there is also a control on the form called Text1.
Text1 = "Variable" ' Variable shadows control.
Me.Text1 = "Control" ' Must qualify with Me to get control.
Text1.Top = 0 ' This causes an error!
Me.Text1.Top = 0 ' Must qualify with Me to get control.
Caption = "Orders" ' Variable shadows property.
Me.Caption = "Orders" ' Must qualify with Me to get form property.
End Sub
You may also have conflicts with the names of your private module-level and public module-level variables and the names of your procedures. A variable in the module can’t have the same name as any procedures or types defined in the module. It can, however, have the same name as public procedures, types, or variables defined in other modules. In this case, when the variable is accessed from another module, it must be qualified with the module name.
While these shadowing rules are not complex, shadowing can be confusing and lead to subtle problems in your code. To avoid these problems, it’s good programming practice to keep the names of your variables distinct from each other. For example, in form or report modules, try to have unique names for properties that are different from names of controls on those forms or reports. This applies to procedure names as well.
In addition to scope, variables also have a lifetime, which is the time during which a variable retains its value. The values in module-level and public variables are preserved as long as the database is open (unless you reinitialize your code). This is true for form and report module-level variables even if you close the form or report. However, local variables declared with the Dim keyword exist only while the procedure in which they are declared is running. Usually, when a procedure has finished, the values of its local variables are discarded and the memory used by the local variables is reclaimed. The next time the procedure is run, all of its local variables are reinitialized. However, you can make Visual Basic preserve the value of a local variable by making the variable static.
To make a local variable in a procedure static, use the Static keyword to declare the variable exactly as you would using the Dim statement.
Static intX As Integer
For example, the following function calculates a running total by adding a new value to the total of previous values stored in the static variable dblAccumulate
.
Function RunningTotal(ByVal dblNum As Double) As Double
Static dblAccumulate As Double
dblAccumulate = dblAccumulate + dblNum
RunningTotal = dblAccumulate
End Function
If you declare dblAccumulate
with the Dim keyword instead of the Static keyword, the previous accumulated values aren’t preserved across calls to the function, and the function simply returns the value with which it was called.
You can produce the same result by declaring dblAccumulate
in the Declarations section of the module, making it a module-level variable. However, after you change the scope of a variable in this way, the procedure no longer has exclusive access to that variable. If other procedures access the value of the variable and change it, the running totals would be unreliable.
To make all local variables in a procedure static, place the Static keyword at the beginning of a procedure declaration, as shown in the following example:
Static Function RunningTotal(ByVal dblNum As Double) As Double
This makes all the local variables in the procedure static, regardless of whether they are declared with the Static or Dim keywords, or declared implicitly. You can place the Static keyword in front of any Function or Sub procedure heading, including event procedures and those that are also declared as Private.