Global variable resets to zero ??? (1 Viewer)

CedarTree

Registered User.
Local time
Today, 14:25
Joined
Mar 2, 2018
Messages
461
Hello - I use globals a lot, esp for a simple project. I set a watch on a global variable for any changes. At the end of one subroutine, the variable = 1000. And the watch flags it for going from the initial zero (I initialize to 0) to 1000. I step through and as soon as we move from that subroutine back to the parent subroutine that called it, the variable gets reset to zero. AND the watch doesn't even catch the change. I've tried recompiling, compacting. Why the reset? Any suggestions please?
 
Proprietary coding so hard to share. Just never saw this before!!!
 
Where is the "Global" variable declared? In a general module or a class module?
 
Not sure if this helps but try declaring the variable as Static.
 
I think I found the issue. I had already declared it as a local variable as well. I would have thought the compiler would have caught that!
 
Last edited:
Why did I do that (b/c I'm an idiot) or why should the compiler have caught it (b/c you are declaring something redundantly and so a least a warning should apply).
 
I would have thought the compiler would have caught that!
Maybe it did but just didn't tell you because I think duplicate names are allowed as long as they are in separate modules. I could be wrong though...
 
My thoughts weŕè scope, where local precedes global.
Another reason to give descriptive names?
 
I think I found the issue. I had already declared it as a local variable as well. I would have thought the compiler would have caught that!
Bit like asking the compiler to ignore the rules it was set with? :)
 
This is a scoping problem. When you have the same name declared in a class module and a general module and you open the form for that particular class module, the variable in the class module is considered local (i.e. closer to) the code that references it. Access - like most languages I know using the "separate module" concept - uses a "scope" or "visibility" rule that says "closest reference wins."

If you are in a class module OTHER than the one that contains the declaration of that variable, the more distant reference wins. Note, however, that there is such a thing as a "friend" declaration for a variable that allows you to qualify your reference to an explicit class module and reference it from another place.

As many of my colleagues have noted, when you have duplicate names (and don't qualify the reference), you get the closest one, which is usually the local definition. So the variable that got updated was in scope when you set it to something other than zero, but when the subroutine exited, it went out of scope and the public variable hadn't been modified away from zero, so that's what you saw.
 
I am not, as many are, totally opposed to Globals. But with the advent of TempVars, tempvars do seem like a better option.
However, I like the explicit typing of globals, and people play awfully fast and loose with temp vars, which I don't like.
Six to one...
 
According to the VBA Language Reference (v20140424) section 5.2.3.1 (Module Variable Declaration Lists), you cannot have duplicate names in any single module's variable declaration area. However, duplication can occur across module boundaries.

Section 5.4 (Procedure Bodies and Statements) and more specifically, section 5.4.3.1 (Local Variable Declarations) says you can have a duplicately named PRIVATE variable declared with in a subroutine or function even if there is a PUBLIC variable of the same name in the module's declaration area, because they are not in the same scope.

A variable defined PRIVATE in a sub or function has "procedure" scope. I.e. not visible outside the procedure where it is defined. Visible only when the defining procedure is actually running.

A variable defined PRIVATE in a sub or function leading declaration area has "module" scope. I.e. not visible outside of the defining module, visible inside the defining module for as long as it exists.

A variable defined PUBLIC in a general module has "project" scope i.e. visible to anything that is part of the project. Visible to any code in any other module in the project.

HOWEVER: A variable declared STATIC, even if in the private variable area of a sub or function, has "module" scope.

The actual "duplicate" name rule is therefore that you can't have duplicate variable names in the same scope. This means that you COULD have private variables named X in every subroutine you create - but if the subroutine is declared PUBLIC and is in a general module, you just elevated the scope of all of the variables.
 
HOWEVER: A variable declared STATIC, even if in the private variable area of a sub or function, has "module" scope.
Are you sure? Or did I miss something?

In a standard module:

Code:
Option Compare Database
Option Explicit

Public Sub Foo()
    Static myStaticVariable As Long
End Sub
                   
Public Sub Bar()
    Debug.Print myStaticVariable ' <-- Compiler raises 'Variable not defined' here
End Sub
 
Why did I do that (b/c I'm an idiot) or why should the compiler have caught it (b/c you are declaring something redundantly and so a least a warning should apply).
You are not alone. I did the exact thing and it had me chasing my tail and "walking the code" for over an hour before I caught it. I wish I could have blamed it on lack of coffee, but the cold, hard truth is that I was just a dumbass....
 
I am not, as many are, totally opposed to Globals. But with the advent of TempVars, tempvars do seem like a better option.
However, I like the explicit typing of globals, and people play awfully fast and loose with temp vars, which I don't like.
Six to one...
Partly for this reason I have wrapper functions for tempvars.

Option Compare Database
Option Explicit

Public Function TempVarsBoolean(ByRef VarName As String) As Boolean
TempVarsBoolean = Nz(TempVars(VarName), False)
End Function

Public Function TempVarsDouble(ByRef VarName As String) As Double
TempVarsDouble = Nz(TempVars(VarName), 0)
End Function

Public Function TempVarsDate(ByVal VarName As String) As Date
If IsDate(TempVars(VarName)) Then
TempVarsDate = DateValue(Nz(TempVars(VarName), #1/1/2099#))
Else
TempVarsDate = #1/1/2099#
End If
End Function

Public Function TempVarsLong(ByVal VarName As String) As Long
TempVarsLong = CLng(Nz(TempVars(VarName), 0))
End Function

Public Function TempVarsString(ByVal VarName As String) As String
TempVarsString = CStr(Nz(TempVars(VarName), "*"))
End Function
 

Users who are viewing this thread

Back
Top Bottom