Solo712
Registered User.
- Local time
- Today, 03:09
- Joined
- Oct 19, 2012
- Messages
- 837
I have recently veered into a discussion about global variables and received a handful of opinions from respectable contributors to AWF ranging from the the standard caution not to overuse them to the view that there is always a better solution than a global variable. I certainly do not accept the latter one, as I would not with any “rules” that are reflective more of a group-thing than a reasoned approach. In fact, in certain situations (spelled out further on) I consider a global variable or a set of globals to be the most logical and appropriate tool to use.
What really whetted my curiosity about the globals now apparently carrying the stigma of a spaggetti go-to factory was the origin of this conviction in the developer community. So I googled and googled to find some sensible discussion about what is good about globals and what is less so. I have not found much that was. I found a lot of shameless babble, though. The standard level of the discussion seemed to converge to this. Globals lead to bad, evil code launching nukes.
If you give pause for some thought to what is being shown and said in the link you will likely find two things: One, the example hopelessly exaggerates the effect of choosing global variables, and two, the silly mistake (of the kind everyone makes all the time) has not anything to do with the use of the global variable as such but rather with reversing the order of processing, in this case that of initializing and, "doing Something" with, the variable. The same type of mistake could have occurred with equal probability using a function or any language resource.
All things told I do think I would be more willing to consider restrictions regarding globals in low-level language like C++ because of the power of the language and its direct contact with some pretty sensitive resources and areas of memory. And yet even there, one gets the feeling the case against the use of global variables tends to be foggy and overstated.
Let’s look for example at the list of objections from here one by one:
It is interesting that after this list of reasons which in his eyes make globals unattractive Rishikesh Parkhe (the writer of the wiki article) makes some very sensible observations in their favour:
As for risks, deriving from the use of globals, in the greatest majority of cases an Access developer will only encounter two:
(1) I have noted one them above, “concurrency”. Your program will need to protect against two or more modules relying on the value same variable and yet both (or all) having access to writing it. You can’t really tell the sequence of events in which the reading / writing occurs because Access is an event-driven environment. How do you mitigate this ?
First, this problem would be way too more pronounced in a multi-user environment, but that level of risk is easily eliminated as an issue via splitting the DB into Front- and Back-End. As for a possible overwriting a global on account of it being shared between several modules at the same workstation, several measures exist, the simplest of which is the habit of setting the variable at the latest and re-initializing it immediately after use, in situations where more than one module can conceivably write into it.
(2) the possibility of serious problems on account of global variables’ getting lost is also a risk. But it is also grossly exaggerated. For starters, there is a very simple solution of how to eliminate this issue entirely and that is compiling the apps into accde form. Then all unhandled errors will terminate the program which solves the problem of “losing the globals” once and for all. This issue really is not as much a probem with the globals per se, but the development environment of Access which continues to miss on an obvious setting to terminate a session on a reset (or going into a design mode)! I have a hard time taking seriously professional developers citing globals as a data security issue. What ? Are they leaving the code in production dbs exposed to the users ? Letting Charlie Regular doing his own debugging ? Would that not be a far greater threat to the integrity of the database than some wily Thief of Baghdad making off with the loot of globals?
There are also some basic rules of thumb that one can follow that dispel much of the mythmaking about the hidden dangers inherent in the use of global variables. And it is mythmaking,make no mistake about it. Because, really there aren’t that many or that big problems despite some people developing a distaste for them by misapprehending the issues due to subscribing to a group-think. Common sense should dictate whether something should be use in place of a global variable.
Best,
Jiri
What really whetted my curiosity about the globals now apparently carrying the stigma of a spaggetti go-to factory was the origin of this conviction in the developer community. So I googled and googled to find some sensible discussion about what is good about globals and what is less so. I have not found much that was. I found a lot of shameless babble, though. The standard level of the discussion seemed to converge to this. Globals lead to bad, evil code launching nukes.
If you give pause for some thought to what is being shown and said in the link you will likely find two things: One, the example hopelessly exaggerates the effect of choosing global variables, and two, the silly mistake (of the kind everyone makes all the time) has not anything to do with the use of the global variable as such but rather with reversing the order of processing, in this case that of initializing and, "doing Something" with, the variable. The same type of mistake could have occurred with equal probability using a function or any language resource.
All things told I do think I would be more willing to consider restrictions regarding globals in low-level language like C++ because of the power of the language and its direct contact with some pretty sensitive resources and areas of memory. And yet even there, one gets the feeling the case against the use of global variables tends to be foggy and overstated.
Let’s look for example at the list of objections from here one by one:
Well, that is strictly QED. Some people write more readable and internally consistent code than others. Some people read code much better than others. The second statement is false. It simply assumes that the programmer does not have control over his program, which is assuming too much. There is no evidence that the memory of a programmer is impaired by the use of globals. It would have sufficed to say that if you use global variables, you need to be aware of them as having global scope and keep accounting of them in that scope.Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
Again, this protests too much. Naturally, if you create software in a team, rules need to be spelled out and adhered to. If a product is the work of a single developer, then it his/her ability to adhere to a plan and understand the effect of design decision that controls the use of resources, not the other way round.No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.) By extension, the lack of access control greatly hinders achieving security in situations where you may wish to run untrusted code (such as working with 3rd party plugins).
I am not sure what specifically the writer has in mind by “coupling”. On the level of logical thought this principle simply assumes something is better than global variables instead of explaining why he thinks it is so.Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.
This of course is an issue, and not only on the thread level. There is a concurrency consideration in Access, specifically with different forms open at the same, theoretically being able to change the value of the variable. This extends further, if the program writes content of global variables into the tables of the database (which I don’t do, btw). So, yes, the effects of concurrency need to be considered.Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected). When dynamically linking modules with globals, the composed system might not be thread-safe even if the two independent modules tested in dozens of different contexts were safe.
No such thingl! There is a very simple way that makes this “pollution” miraculously disappear – at once. (see below).Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.
Not all that applicable to Access except perhaps when doing some fancy work with COMs, custom OCX modules DLLs, etc.Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.
This again relates mostly to dev environments other than ours. In Access testing, the globals do not have any negative effect (that I am aware of) as the debug mode preserves the contents of all globals which aids in many instances in stepping through the execution.Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. More generally, source that utilizes global services of any sort (e.g. reading and writing files or databases) that aren't explicitly provided to that source is difficult to test for the same reason. For communicating systems, the ability to test system invariants may require running more than one 'copy' of a system simultaneously, which is greatly hindered by any use of shared services - including global memory - that are not provided for sharing as part of the test.
It is interesting that after this list of reasons which in his eyes make globals unattractive Rishikesh Parkhe (the writer of the wiki article) makes some very sensible observations in their favour:
Now, of course, the question is “what is a global” ? I would say that a variable that holds data used by more than two forms / reports / modules, either throuout a session, or intermittently would most likely qualify for the honours. For my own purposes I routinely use global variables:Why the Convenience of Global Variables Sometimes Outweighs the Potential Problems
• In a very small or one-off programs, especially of the 'plugin' sort where you're essentially writing a single object or short script for a larger system, using globals can be the simplest thing that works.• When global variables represent facilities that truly are available throughout the program, their use simplifies the code.• Some programming languages provide no support or minimal support for non-global variables.
N/A• Some people jump through very complicated hoops to avoid using globals. Many uses of the SingletonPattern are just thinly veiled globals. If something really should be a global, make it a global. Don't do something complicated because you might need it someday.(my emphasis) If a global variable exists, I would assume that it is used. If it is used, there are methods associated with it. Colocate those methods in a single class and one has created a singleton. It really is better to specify all of the rules for use of a global variable in one place where they can be reviewed for consistency. The veil may be thin, but it is valuable.
a. to set up and maintain session parameters: login status, name of logged in users, their privilege code, license info, activity marker for timer events (timeout), messages for custom message boxes, switches (read by master timer), etc.
b. to maintain settings of forms: screen positions of popups, special effects, color schemes, etc.
c. to pass strings around to forms (eg. custom splash screens) and report (mostly subheadings based on user report selection).
d. For Whiteboard data in broadcasts or alerts about upcoming calendar events.
e. For data structures used to set up queries.
f. For switches controlling program execution (eg. release of quasi-dialog forms).
g. For session counters, and routine calculations used in decisions to trigger events.
e. For data structures used to set up queries.
f. For switches controlling program execution (eg. release of quasi-dialog forms).
g. For session counters, and routine calculations used in decisions to trigger events.
As for risks, deriving from the use of globals, in the greatest majority of cases an Access developer will only encounter two:
(1) I have noted one them above, “concurrency”. Your program will need to protect against two or more modules relying on the value same variable and yet both (or all) having access to writing it. You can’t really tell the sequence of events in which the reading / writing occurs because Access is an event-driven environment. How do you mitigate this ?
First, this problem would be way too more pronounced in a multi-user environment, but that level of risk is easily eliminated as an issue via splitting the DB into Front- and Back-End. As for a possible overwriting a global on account of it being shared between several modules at the same workstation, several measures exist, the simplest of which is the habit of setting the variable at the latest and re-initializing it immediately after use, in situations where more than one module can conceivably write into it.
(2) the possibility of serious problems on account of global variables’ getting lost is also a risk. But it is also grossly exaggerated. For starters, there is a very simple solution of how to eliminate this issue entirely and that is compiling the apps into accde form. Then all unhandled errors will terminate the program which solves the problem of “losing the globals” once and for all. This issue really is not as much a probem with the globals per se, but the development environment of Access which continues to miss on an obvious setting to terminate a session on a reset (or going into a design mode)! I have a hard time taking seriously professional developers citing globals as a data security issue. What ? Are they leaving the code in production dbs exposed to the users ? Letting Charlie Regular doing his own debugging ? Would that not be a far greater threat to the integrity of the database than some wily Thief of Baghdad making off with the loot of globals?
There are also some basic rules of thumb that one can follow that dispel much of the mythmaking about the hidden dangers inherent in the use of global variables. And it is mythmaking,make no mistake about it. Because, really there aren’t that many or that big problems despite some people developing a distaste for them by misapprehending the issues due to subscribing to a group-think. Common sense should dictate whether something should be use in place of a global variable.
• The first decision point I believe should be why not a global variable ? It is because whatever its shortcomings, a global variable will almost always be the simplest solution in passing data around Access objects. As Rishikesh says, “using globals can be the simplest thing that works”. Then why would one want to use something more complicated?
• Well, one usually wouldn’t use something more complicated but one would not want to fall into an indiscriminate use of globals, either. They may sometimes be clearly an overkill. There is a reason for scoping, and it is to keep resources used to accomplish something to a minimum. Don’t bring howitzer to swat a fly! It’s a good policy that helps to assure well-run programs. So if the scope for the variable is local (within a procedure) it should be local, if it is class then it should be class, and if it is global, then, yea Lord, there is no reason why it should not be global. “Don’t do something complicated” just because you think globals are bad, and experts would not use them. Use the least costly solution in terms of resources to get something done! If it is a global variable, it is a global variable.
• All that said, if you use globals, perhaps a few common-sense rules and testing of code should be observed:
If you don’t use globals, consider these options:
• In preference to manipulating Dialog forms to hidden and then closing them, you can open them as normal popup and then inhibit the return to the calling form until the called popup closes. While the popup remains open you can address the objects of the calling form directly as ([Forms]![CallingForm]![aControl]). The behaviour of this form will be the the same as the one open in a dialog mode without the restrictions attendant to the former. The user will not be able to interact with other form than the popup but the VBA code will have free access to all resources normally at its disposal.
This technique has a great potential in that it allows a sophisticated interaction between the two forms. In effect, it allows the execution loop to do stuff to the calling form based on commands from the Popup form. (I will be demo’ed soon in my own design of a generic Find Record utility)
• For session variables, i.e. persistent values that govern the behaviour of the forms, placements of objects, their visibility, colors etc. past a single session consider an excellent utility by Juan Soto. I am seriously considering using it.
• Well, one usually wouldn’t use something more complicated but one would not want to fall into an indiscriminate use of globals, either. They may sometimes be clearly an overkill. There is a reason for scoping, and it is to keep resources used to accomplish something to a minimum. Don’t bring howitzer to swat a fly! It’s a good policy that helps to assure well-run programs. So if the scope for the variable is local (within a procedure) it should be local, if it is class then it should be class, and if it is global, then, yea Lord, there is no reason why it should not be global. “Don’t do something complicated” just because you think globals are bad, and experts would not use them. Use the least costly solution in terms of resources to get something done! If it is a global variable, it is a global variable.
• All that said, if you use globals, perhaps a few common-sense rules and testing of code should be observed:
a. make their scope known by naming them as globals, e.g. by a prefix “glb”, “g” or some such.
b. Make a habit of controling/checking which part(s) of the program write globals and (where applicable) keep the source of writing to a minimum (even at the cost of splitting the variable into two or three). Concurrency issues arise from writing variables, not reading them !
c. Learn to distinguish between different uses of globals. There may be variables that are session parameters, those controlling the settings of different forms, messages, flags, switches, etc. Some are transient settings controlling program flow. Some require more attention than others.
d. You may want to keep global variables (and constants) in a single standard module. Keep the different functional groups together as sections. This definitely helps orientation in a larger project. Comments on use will be welcome by anyone coming to admire your work.
e. In a serial use of a global variable, reset it to “empty” after each use. For Chrissakes!
f. In a dev environment, protect the modules against the loss of globals (those that have more than transient signifiance) by testing for a non-zero value in one of them and reloading the set if necessary in the form’s On Load event. (I usually leave this code in even in the accde, as it might be useful in the next version of the app).
g. Distribute production Access applications in accde format!
h. Don’t follow the leaders, watch the parking meters !
b. Make a habit of controling/checking which part(s) of the program write globals and (where applicable) keep the source of writing to a minimum (even at the cost of splitting the variable into two or three). Concurrency issues arise from writing variables, not reading them !
c. Learn to distinguish between different uses of globals. There may be variables that are session parameters, those controlling the settings of different forms, messages, flags, switches, etc. Some are transient settings controlling program flow. Some require more attention than others.
d. You may want to keep global variables (and constants) in a single standard module. Keep the different functional groups together as sections. This definitely helps orientation in a larger project. Comments on use will be welcome by anyone coming to admire your work.
e. In a serial use of a global variable, reset it to “empty” after each use. For Chrissakes!
f. In a dev environment, protect the modules against the loss of globals (those that have more than transient signifiance) by testing for a non-zero value in one of them and reloading the set if necessary in the form’s On Load event. (I usually leave this code in even in the accde, as it might be useful in the next version of the app).
g. Distribute production Access applications in accde format!
h. Don’t follow the leaders, watch the parking meters !
If you don’t use globals, consider these options:
• In preference to manipulating Dialog forms to hidden and then closing them, you can open them as normal popup and then inhibit the return to the calling form until the called popup closes. While the popup remains open you can address the objects of the calling form directly as ([Forms]![CallingForm]![aControl]). The behaviour of this form will be the the same as the one open in a dialog mode without the restrictions attendant to the former. The user will not be able to interact with other form than the popup but the VBA code will have free access to all resources normally at its disposal.
Code:
‘in a calling from
DoCmd.OpenForm “PopupAccessingMyControls”
Do While IsLoaded("PopupAccessingMyControls ")
DoEvents
Loop
‘---------------------------------------------------------------
‘ in a standard module
Public Function IsLoaded(ByVal strFormName As String) As Boolean
' Returns True if the specified form is open in Form view or Datasheet view.
Const conObjStateClosed = 0
Const conDesignView = 0
If SysCmd(acSysCmdGetObjectState, acForm, strFormName) <> conObjStateClosed Then
If Forms(strFormName).CurrentView <> conDesignView Then
IsLoaded = True
End If
End If
End Function
This technique has a great potential in that it allows a sophisticated interaction between the two forms. In effect, it allows the execution loop to do stuff to the calling form based on commands from the Popup form. (I will be demo’ed soon in my own design of a generic Find Record utility)
• For session variables, i.e. persistent values that govern the behaviour of the forms, placements of objects, their visibility, colors etc. past a single session consider an excellent utility by Juan Soto. I am seriously considering using it.
Best,
Jiri
Last edited: