Scope & Lifetime    


As programs get larger, the number of identifiers increases. Some of these identifiers are declared inside blocks. Other identifiers--procedure names, for example--are declared outside of any block. Scope rules govern the way in which a procedure may access identifiers declared outside its own block.


Scope of Identifiers

Local variables are those declared inside a block, such as the body of a procedure. Local variables cannot be accessed outside the block that contains them. The same access rule applies to local named constants: they can be accessed only in the block in which they are declared.

If we list all the places from which an identifier could be accessed legally, we would describe that identifier's scope of visibility or scope of access, often just called its scope.

There are two categories of scope for any identifier.*

  1. Local scope. The scope of an identifier declared inside a block extends from the point of declaration to the end of that block.
  2. Global (or module) scope. The scope of an identifier declared in the general declarations is called a module-level declaration and extends from the point of declaration to the end of the entire file containing the program code. These are also referred to as global variables.

Procedure names have global scope. Once a procedure name has been declared, it can be invoked by any other procedure in the rest of the program. In VB there is no such thing as a local procedure--that is, you cannot nest a procedure definition inside another procedure.

Global variables and constants are those declared outside all procedures. When a procedure declares a local identifier with the same name as a global identifier, the local identifier takes precedence within the procedure. This principle is called name precedence or name hiding.

Here's an example that uses both local and global declarations:

In this example, procedure someSub accesses global constant CONST1 but declares its own local variables var1 and uses parameter var2. Thus, the output would be

 Const1 = 17 var1 = 2.3 var2 = 42.8

 

Local variable var1 takes precedence over global variable var1, effectively hiding global var1 from the statements in procedure someSub. Formal parameter var2 also blocks access to global variable var2 from within the procedure. Formal parameters act just like local variables in this respect.

When you write VB programs, you rarely declare global variables. There are negative aspects to using global variables, but when a situation crops up where you have a compelling need for global variables, it pays to know how VB handles these declarations. The rules for accessing identifiers that aren't declared locally are called scope rules.

Here are the detailed scope rules:

  1. A procedure name has global scope. Procedure definitions cannot be nested within procedure definitions.
  2. The scope of a formal parameter is identical to the scope of a local variable declared in the procedure body
  3. The scope of a global variable or constant extends from its declaration to the end of the file.
  4. The scope of a local variable or constant extends from its declaration to the end of the block in which it is declared.
  5. The scope of an identifier does not include any nested block that contains a locally declared identifier with the same name (local identifiers have name precedence).

Note: You cannot declare a local variable in a procedure with the same identifier as a parameter in the procedure's parameter list.

Here is a sample program that demonstrates scope rules To simplify the example, only the declarations and headings are spelled out.

Let's look at the ScopeRules program in terms of the blocks it defines and see just what these rules mean. The figure below shows the headings and declarations in the ScopeRules program with the scopes of visibility indicated by boxes.

Anything inside a box can refer to anything in a larger surrounding box, but outside-in references aren't allowed. Thus, a statement in block2 could access any identifier declared in the general declarations. A statement in block2 cannot access identifiers declared in block1 because it would have to enter the block1 box from outside.

Notice that the formal parameters for a procedure are inside the procedure's box, but the procedure name itself is outside. If the name of the procedure were inside the box, no procedure could call another procedure. This demonstrates merely that procedure names are globally accessible.

Imagine the boxes in the figure as rooms whose walls are made of two-way mirrors, with the reflective side facing out and the see-through side facing in. If you stood in the room for block2, you would be able to see out through the surrounding rooms to the declarations of the global variables. You would not be able to see into any other rooms (such as block1), however, because their mirrored outer surfaces would block your view. Because of this analogy, the term visible is often used in describing a scope of access. For example, variable a2 is visible throughout the program, meaning that it can be accessed from anywhere in the program.

The figure does not tell the whole story; it represents only scope rules 1 through 4. We also must keep rule 5 in mind. Variable a1 is declared in two different places in the ScopeRules program. Because of name precedence, block2 accesses the al declared in block2 rather than the global a1.

Name precedence is implemented by the compiler as follows: When a statement refers to an identifier, the compiler first checks the local declarations. If the identifier isn't local, the compiler works its way outward through each level of nesting until it finds an identifier with the same name. There it stops. If there is an identifier with the same name declared at a level even further out, it is never reached. If the compiler reaches the global declarations and still can't find the identifier, an error message--Name is not declared--will result.

Such a message most likely indicates a misspelling or an incorrect capitalization, or it could mean that the identifier was not declared before the reference to it or was not declared at all. It may also indicate, however, that the identifier's scope doesn't include the reference.


Lifetime of a Variable

A concept related to but separate from the scope of a variable is its lifetime--the period of time during program execution when an identifier actually has memory allocated to it. Storage for local variables is allocated at the moment control enters a procedure. Then the variables are "alive" while the procedure is executing, and finally the storage is deallocated when the procedure exits. In contrast, the lifetime of a global variable is the lifetime of the entire program. Global memory space is allocated only once, when the program begins executing, and is deallocated only when the entire program terminates. Observe that scope is a compile-time issue, but lifetime is a run-time issue.

In VB, each variable has a storage class that determines its lifetime. An automatic variable is one whose storage is allocated at block entry and deallocated at block exit. A static variable is one whose storage remains allocated for the duration of the entire program. All global variables are static variables. By default, variables declared within a block are automatic variables. However, you can use the reserved word Static when you declare a local variable. If you do so, the variable is a static variable and its lifetime persists from procedure call to procedure call:

It is usually better to declare a local variable as Static than to use a global variable. Like a global variable, its memory remains allocated throughout the lifetime of the entire program. But unlike a global variable, its local scope prevents other procedures in the program from accessing it.

More details on Scope.