Variables – Part 2
Declaration and Scope
What is Scope?
The scope (or visibility) of an element in code is all the code that can refer to it without qualifying its name. Stated other way, an element's scope is it's accessibility in code. Scope is normally used when writing large programs as large programs divide code into different classes, modules, etc. Also, scope prevents the chance of code referring to the wrong item.
The syntax for declaring a variable in VB is as follows:
[Dim | Private | Public | Static | Protected | Friend | Protected Friend] variablename [As datatype]
Note that you use one of seven keywords to declare a variable; which one you use depends on the scope you want the variable to have. Levels of scope are:
· project-level (also called "global" or "application" scope; the variable is accessible to all procedures in all modules of the project)
· module-level (the variable is accessible to all procedures in the module in which it is declared)
· local-level (the variable is accessible only to the procedure in which it is declared)
· block level (the element declared is available only within the code block in which it is declared)
In addition to the keyword used to declare the variable, the location of the variable declaration also affects its scope. A variable may be declared in one of two places:
· The General Declarations Section of a form or standard module. This section of a module is not labeled as such; it simply exists at the beginning of a code module, after the "Option Explicit" statement but prior to the first Sub or Function procedure. Declaring a variable here makes it a project-level variable (if the Public keyword is used) or a module-level variable (if the Private or Dim keyword is used).
· Within a Sub or Function procedure. Declaring a variable here makes it a local-level variable; only the Dim or Static keyword can be used here. The recommended practice is to declare all local variables within a procedure immediately following the Sub or Function header and prior to any executable statements (although VB will allow you to declare variables anywhere within the procedure).
Accessibility means the permission for code to read or write to an element. In other words, it’s the restriction to access the element (variable or subroutines) which is decided by you using the keywords mentioned above, these keywords are also known as Access Modifiers. The table below shows the access modifiers in detail:
Access Modifier |
Affect on Elements |
Public |
Can be accessed from anywhere. |
Private |
Can be accessed only by members within the type that defines it. |
Friend |
Can be accessed from all types within the assembly, but not from outside the assembly. |
Protected |
Can be accessed only by members within the type that defines it or types that inherit from that type. |
Protected Friend |
Can be accessed from all types within the assembly or from types inheriting from the owning type. This is the union of Protected (protected) and Friend (internal) access. |
The following table shows how the seven different declarative keywords and the location of their declaration affects the scope:
Keyword Used to Declare the Variable: $ |
Where Declared à |
General Declarations Section of a Form (.frm) Module |
General Declarations Section of a Standard (.bas) Module |
Sub or Function procedure of a Form or Standard Module |
Dim (preferred keyword for local-, but not module-level variables) |
module-level scope |
module-level scope |
local-level scope (value of the variable is NOT preserved between calls |
|
Static |
not allowed |
not allowed |
local-level scope (value of the variable is preserved between calls) |
|
Private (preferred keyword for module-level variables) |
module-level scope |
module-level scope |
not allowed
|
|
Public |
project-level scope (but references to the variable must be qualified with the form name; also there are some minor restrictions on the types of variables that can be declared as public in a form) |
project-level scope |
not allowed |
|
Protected |
Module- level scope |
Module-level scope |
not allowed |
|
Friend (This is only allowed in classes not in standard modules) |
Assembly level scope |
not allowed |
not allowed |
|
Protected Friend (This is only allowed in classes not in standard modules) |
Assembly level scope |
not allowed |
not allowed |
If the "As datatype" clause is omitted in a variable declaration, the variable type defaults to Object, unless a type declaration character is used. (Note: In previous versions of VB, the default data type was Variant, which does not exist in VB.NET.)
The following two statements both declare an integer called "intCounter" (the "As" version is preferred):
Dim intCounter As Integer
Dim intCounter%
The following two statements both declare an Object variable called "objWhatever":
Dim objWhatever As Object
Dim objWhatever
In VB .NET the String variables can be only of variable-length, and not fixed-length (as was allowed in VB6 and earlier). The difference in declaring them is shown below:
'Variable-length string, length changes depending upon length of whatever is assigned to it:
Dim strPlayerName As String
'Fixed-length string, always 2 bytes (legal in VB6 and earlier, illegal in VB.NET)
Dim strStateAbbrev As String * 2 ' ILLEGAL IN VB.NET
Note: Protected, Friend, or Protected Friend will not be used in the sample applications presented here.
Static Variables
The Static keyword is rarely used. It allows a local variable to retain its value after it goes out of scope.
Suppose you have a Sub in a form called CountThem that looks like this:
Private Sub CountThem()
Dim intI As Integer
Static intJ As Integer
intI = intI + 1
intJ = intJ + 1
Debug.Print("intI = " & intI & ", intJ = " & intJ)
End Sub
Suppose you have some other Sub that calls CountThem three times in a row:
Call CountThem
Call CountThem
Call CountThem
The following output from Debug.Print would be as follows:
intI = 1, intJ = 1
intI = 1, intJ = 2
intI = 1, intJ = 3
Note that the "regular" variable, intI, declared with "Dim", does not retain its value between calls, whereas the Static variable, intJ, does. Rather than use “Static”, it would be preferred to declare “intJ” at the module- or form-level (i.e. outside of all the Sub and Function procedures, with the keyword “Private” or “Dim”).
Note: In VB6, the keyword "Static" can also be used in the Sub procedure header, which causes all variables in that procedure to be static. This option is no longer available in VB.NET (i.e., the static modifier is not a valid modifier for procedure).
VB .NET allows you to declare any number of variables on one line – you don’t need to explicitly provide the data type of each variable, For example:
Dim intA, intB, intC As Integer
The above statement declares intA and intB and intC as Integer type values.
I recommend declaring only one variable per line.
Variables can be declared and initialized in Visual Basic .NET on a single line. Thus you may write:
Dim strVar As String = "This is a string."
The above statement declares a String variable and initializes its value to “This is a string”. Similarly, you can declare and initialize more than one variable on a single line:
Dim intX As Integer = 6, intY As Integer = 9
However, each variable does have a default initialization value. Numeric variable types are initialized to zero, Strings are initialized to "", Booleans are initialized to False, etc.
The Strict and Explicit options
Previous versions of VB (classic VB), as well as BASIC before that, did not require that variables be declared before they were used. VB.NET also carries on this “tradition” in permitting this practice, however the default behavior of VB.NET is to throw an exception if you attempt to use a variable that hasn’t been declared previously. If an undeclared variable’s name appears in your code, the editor will underline the variable’s name with a wiggly red line indicating that it caught an error. Rest the mouse pointer on that line to see the description of the error. This means that Option Explicit is on – that is the default setting, and you should keep it that way.
Another related option is Option Strict, which is OFF by default. Option Strict tells the compiler whether the variables should be strictly typed or not. A strictly typed variable can only accept values of the same type it was declared with. Some purists will advocate that this option be turned on, however I am of the opinion that this option is too restrictive and I am fine with leaving the default setting (off) as is.
LEGAL VS. ILLEGAL VARIABLE DECLARATIONS
The figure below attempts to highlight concepts of variable declaration and scoping discussed previously:
PROJECT |
(Form1) Public Class Form1
'General Declarations Section …
Public intA As Integer Private intB As Integer
Private Sub MySub1()
Dim intC As Integer
intC = intA 'OK – intA is public (declared in this form) intC = intW 'OK – intW is public (declared in Module1) intC = intB 'OK – intB is a module-level variable of this form intC = intD 'Error – intD is local to MySub2 intC = intX 'Error – intX is private to Module1
End Sub
Private Sub MySub2()
Dim intD As Integer
intD = intA 'OK – intA is public (declared in this form) intD = intW 'OK – intW is public (declared in Module1) intD = intB 'OK – intB is a module-level variable of this form intD = intC 'Error – intC is local to MySub1 intD = intX 'Error – intX is private to Module1
End Sub
End Class
|
(Module1) Module Module1
'General Declarations Section ... Public intW As Integer Private intX As Integer
Public Sub MySub3()
Dim intY As Integer
intY = intA 'Error – qualification required intY = Form1.intA 'OK – intA is public (declared in Form1) intY = intW 'OK – intW is public (declared in this module) intY = intX 'OK – intX is a module-level variable of this module intY = intZ 'Error – intZ is local to MySub4 intY = intB 'Error – intB is private to Form1 intY = Form1.intB 'Ditto
End Sub
Public Sub MySub4()
Dim intZ As Integer
intZ = intA 'Error – qualification required intZ = Form1.intA 'OK – intA is public (declared in Form1) intZ = intW 'OK – intW is public (declared in this module) intZ = intX 'OK – intX is a module-level variable of this module intZ = intY 'Error – intY is local to MySub3 intZ = intB 'Error – intB is private to Form1 intZ = Form1.intB 'Ditto
End Sub
End Module |