[AccessD] Global Variable

DWUTKA at marlow.com DWUTKA at marlow.com
Tue May 17 19:02:29 CDT 2005


I would not agree that a global should be used there, it is not declared for
scope, but for convenience.

Drew

-----Original Message-----
From: Dan Waters [mailto:dwaters at usinternet.com]
Sent: Tuesday, May 17, 2005 6:05 PM
To: 'Access Developers discussion and problem solving'
Subject: RE: [AccessD] Global Variable


Drew,

I'm making them global purely for my convenience.  I use these variables in
perhaps hundreds of procedures and functions.  Dimensioning them once as
global variables in a standard module instead of in every form, report, or
standard module is much more convenient.  It would be more technically
correct to Dimension these variables in each procedure or function where
they are used.

The value in these variables will be lost if there is an unhandled error,
but it doesn't matter because the value I'm interested in only lasts until
that value is passed to the GlobalErrors procedure.  Also, I don't use these
variables in any other context throughout my applications.

The reason I use a variable at all is that both Err.Number and
Err.Description are 'one-trick ponies'.  As soon as you use them in an
expression, the value of each goes to null.  So, because I want to use the
value of Err.Number in a Select Case and also pass it to GlobalErrors, I
first have to read the value to a Dimensioned variable which will maintain
the value of the error number.

Dan Waters


-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com] On Behalf Of DWUTKA at marlow.com
Sent: Tuesday, May 17, 2005 10:27 AM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Global Variable

I just skimmed to the bottom, where you are setting both variables to the
Err objects Number and description.  If those are global, I would wonder
why...because you are passing them through a function.  The function is
receiving the values they represent, so why make them global?

Drew

-----Original Message-----
From: Dan Waters [mailto:dwaters at usinternet.com]
Sent: Monday, May 16, 2005 7:34 PM
To: 'Access Developers discussion and problem solving'
Subject: RE: [AccessD] Global Variable


Drew,

Yes, I also put error handling into almost all procedures.  Below is an
directly copied example of a public procedure that I keep in a standard
module.

Errors are collected in a table, and when the first person at a customer
site opens the app, the contents of the table are placed in the message of
an email and sent to me in the background.  This way I can play 'mother
ship' and all my children tell me how they're doing every day! 

A TEST FOR YOU:  Look at GlngErrNumber and GstgErrDescription.  Why am I
doing this and why is it OK?

Dan Waters


Public Sub CreateCustomSpreadsheet(stgProcessName As String, stgSQL As
String)
If ErrorTrapping = True Then On Error GoTo EH

    '-- This will create a spreadsheet based on user criteria from the
different custom reporting screens

    Dim fso As FileSystemObject
    Dim stgFolderName As String
    Dim stgSpreadsheetName As String
    Dim frm As Form

    If stgProcessName = "AllBackups" Then
        Set frm = Forms("frmPeopleCustomReports")
    Else
        Set frm = Forms("frm" & stgProcessName & "CustomReports")
    End If

    Set fso = CreateObject("Scripting.FileSystemObject")
    stgFolderName = "C:\" & SystemAcronym & "\"
    If fso.FolderExists(stgFolderName) = False Then
        fso.CreateFolder (stgFolderName)
    End If
    stgFolderName = "C:\" & SystemAcronym & "\Spreadsheets\"
    If fso.FolderExists(stgFolderName) = False Then
        fso.CreateFolder (stgFolderName)
    End If
    Set fso = Nothing
    stgSpreadsheetName = SystemAcronym & " " & stgProcessName & " Custom " &
CurrentDateTimeString & ".xls"
    Select Case stgProcessName
        Case "DBM"
            DBEngine(0)(0).QueryDefs("qryDBMCustomSpreadsheet").SQL = stgSQL
        Case "SDEV"
            DBEngine(0)(0).QueryDefs("qrySDEVCustomSpreadsheet").SQL =
stgSQL
        Case "CAPA"
            DBEngine(0)(0).QueryDefs("qryCAPACustomSpreadsheet").SQL =
stgSQL
        Case "People"
            DBEngine(0)(0).QueryDefs("qryPeopleCustomSpreadsheet").SQL =
stgSQL
        Case "InspectionBatchCreate"
 
DBEngine(0)(0).QueryDefs("qryInspectionBatchCreateCustomSpreadsheet").SQL =
"SELECT * FROM tblInspectionBatchCreate IN '" & BEFullPath & "' WHERE " &
stgSQL
        Case "InspectionBatchData"
 
DBEngine(0)(0).QueryDefs("qryInspectionBatchDataCustomSpreadsheet").SQL =
stgSQL
        Case "AllBackups"
            '-- The qryAllBackupsCustomSpreadsheet simply picks up the
entire tblFEAllBackups table
        Case Else
            DBEngine(0)(0).QueryDefs("qry" & stgProcessName &
"CustomSpreadsheet").SQL = "SELECT * FROM tbl" & stgProcessName & "Main IN
'" & BEFullPath & "' WHERE " & stgSQL
    End Select
    DoCmd.TransferSpreadsheet acExport, , "qry" & stgProcessName &
"CustomSpreadsheet", stgFolderName & stgSpreadsheetName
    If FormattedMsgBox(GstgQuestion, "The spreadsheet titled " _
        & vbCrLf & vbCrLf _
        & stgSpreadsheetName _
        & vbCrLf & vbCrLf _
        & " has been created in the C:\" & SystemAcronym & "\Spreadsheets
folder on your PC." _
        & vbCrLf & vbCrLf & vbCrLf _
        & "Do you want to open that spreadsheet now?@ @", vbYesNo +
vbDefaultButton1, "Spreadsheet Created") = vbYes Then
        If stgProcessName = "AllBackups" Then
            frm!butAllBackupsSpreadsheet.HyperlinkAddress = stgFolderName &
stgSpreadsheetName
            frm!butAllBackupsSpreadsheet.Hyperlink.Follow
        Else
            frm!butSpreadsheetHyperlink.HyperlinkAddress = stgFolderName &
stgSpreadsheetName
            frm!butSpreadsheetHyperlink.Hyperlink.Follow
        End If
    End If

    Exit Sub

EH:
    Application.Echo True
    DoCmd.Hourglass False
    GlngErrNumber = Err.Number
    GstgErrDescription = Err.Description
    Select Case GlngErrNumber
        Case 58  '-- Folder already exists
            Resume Next
        Case 287
            '-- User chose to cancel after 'virus' warning message
            Resume Next
        Case Else
            Call GlobalErrors("", GlngErrNumber, GstgErrDescription, "Create
Custom Spreadsheet", "CreateCustomSpreadsheet")
    End Select

End Sub



-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com] On Behalf Of DWUTKA at marlow.com
Sent: Monday, May 16, 2005 5:09 PM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Global Variable

Okay, now I can't tell if you are being sarcastic or not.  If you think
module AND global level variables are bad practice....well, that only leaves
procedural, and you might as well stop programming....  

You CAN be 100% sure that you don't have unhandled errors.  Put Error
handling procedures into every procedure!  Now that is a GOOD practice.
Admittedly, I don't do that myself, not on personal stuff...... (now THAT,
I'm willing to concede is a bad practice! <grin>).  

If you can be sure you're not using global variables (or modular level),
then you could also be sure that you have no unhandled errors!

Maybe you don't understand this, so I'll explain this for you, please don't
think I'm trying to be obnoxious, but if you don't understand error
handling, then it would explain your statements below.

One, If you start every procedure (Function or Sub (and Property statements
in classes)) with On Error statements, you cannot have an unhandled error.

On Error Resume Next will simply let every error just pass right through the
system.  Obviously...not smart, but sometimes it is actually necessary.  

On Error Goto 

Well, with that statement, you can force the code to go to an 'Error
Handler', where you can do all sorts of things.  You can accomodate an error
(sometimes, you program expecting an error to occur, so getting into the
errorhandler is by design in those cases).  Let's say that you put in
ErrorHandling when a user puts text data into a numeric field.  Now, let's
say that you might expect the user to type 'one', instead of '1'.  You may
decide to create a text to number function, so that the user never knows
something is wrong, you fix the issue, and continue your code.  To do that,
your errorhandler has to determine if the error applies (wrong data type in
that case).  Even if you don't know what type of error it is, you can always
display the error number and description, and move on. (Use a Select Case
statement in the errorhandler...and include the Case Else statement).
Either way, if you have Errorhandling in your procedures, you'll never have
the code stopped by the user (unless you let them get into your code!).

The only time this does NOT apply, is when you have an exception fault.
Yes, you can cause that from within VBA...don't ask  me how, cause I'm
drawing a blank, but I've done it before! <grin>  In cases like that, the
Error handling isn't triggered....instead, ACCESS gets shut down.  If that
happens, it doesn't really matter that the global variables will be lost,
because EVERYTHING is lost!

Does that make sense?

Drew

-----Original Message-----
From: Dan Waters [mailto:dwaters at usinternet.com]
Sent: Monday, May 16, 2005 4:45 PM
To: 'Access Developers discussion and problem solving'
Subject: RE: [AccessD] Global Variable


Drew,

Globals are bad practice because:

If I use global variables and I have an unhandled error I can be 100% sure
that my global variable value will be lost.

I cannot be 100% sure that I won't have unhandled errors.

I can be 100% sure that I'm not using global variables.  

If I could be 100% certain that I won't have unhandled errors, then global
variables would be a good practice.  

Dan Waters

PS - Based on what you pointed out about module level variables, I think
using them is bad practice too!  See - I learned something new because you
told me 'why'!

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com] On Behalf Of DWUTKA at marlow.com
Sent: Monday, May 16, 2005 3:53 PM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Global Variable

Right, but it's a jaded, and actually illogical proclamation that Globals
are bad practice. 

Let's look at this Dan.  What's the argument that they are bad practice?
Because stopping the code makes them lose their values.  Okay, that is true,
but does it apply to anything else?  It sure does, but the 'general
consensus' folks are only worried about Globals.  Why?  Who knows.  Let's
test our theory.

Make a form, and put three command buttons on it.  Now paste the following
code behind the form (and set the events for the form's load, and the
command buttons 'On Click' events.

Option Compare Database
Option Explicit
Private intSomeNumber As Long
Private Sub Command0_Click()
intSomeNumber = 5
End Sub

Private Sub Command1_Click()
MsgBox intSomeNumber
End Sub

Private Sub Command2_Click()
Dim x As Long
x = 1 / 0
End Sub

Private Sub Form_Load()
intSomeNumber = 1
End Sub

Open the form, and hit the first button.  Now hit the second button.  We get
5.  Close the form, open the form, and hit the second button.  We get 1.
All as expected right?  Now hit the third button...uh oh, an error, it's not
handled.  Now hit 'end' (which stops the code from executing).  To the user,
the error is 'over'.  Nothing to worry about, right?  Wrong, we just lost
ALL variables.  Hit the second button now, we get a big ZERO!!!!  Now, if we
say that global variables are bad practice, because they lose their value
when the code is stopped from an unhandled error, shouldn't we also say that
module level variables are bad practice?

If we dimensioned intSomeNumber as 'Public MyNumericValue', which takes a
module level variable, and makes it a PROPERTY of the form, we get the same
results.  The stop in the execution of the code cause the property to lose
it's value!  So should we also apply the 'bad practice' principle to class
properties?

Of course not, because we'd be left with procedural level variables, which,
by the way, ALSO lose their values when the code is stopped, but that is
completely unnoticed, since the procedure being run just stopped!

Now, let's change Command2_Click() to this:

Private Sub Command2_Click()
On Error GoTo ErrorHandler
Dim x As Long
x = 1 / 0
Exit Sub

ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Err.Clear
End Sub

Now, same process, and look at that...the values are still there.  (so would
the values in a global variable, and a class property).  Now, tell me Dan,
which is bad practice?  Global Variables, or missing/improper error
handling?  

Eh?

Now for why I get into this type of discussion, and why I may appear to
'rail' against the norm.  Let's take Jim Bob the new developer.  He's just
starting out in coding, but is a very fast learner.  He's tearing through
using classes, and creating custom events, and is progressing at an amazing
pace.  He's done this, of course, by being an avid reader on AccessD.  Now,
he's seen posts from people like Charlotte, and JC, people who's coding and
experience is nothing but impressive.  He sees a post by them that says
'Don't get carried away with them, they are considered bad practice in
general.'.  Now, whether or not Jim Bob the Developer has specifically had
one of them help him with his code, he has more then likely made use of the
knowledge he has gleaned from their posts.  Now he is in a situation where
using Global variables is the best solution.  He may have to use a lot of
them.  But it all works just fine, and does exactly what it's supposed to
do.  But wait a minute, people he respected, and simply took their word as
law in the coding world said that it was 'bad practice'.  There must be
something he doesn't know about global variables.  It's 'iffy'.  That's the
concept that comes across.  So he doesn't use Global Variables.  Instead, he
writes 5 times more code (ya, look at the typing difference between Global
XYZ, and a function to handle preloading etc....) or more, and now his code
is NOT as efficient as it should be, and he's wasting time.

What's worse, is that when Jim Bob the Developer starts posting to AccessD
as Jim Bob the experienced and world renowned developer, he is going to tell
Jim Bob Junior, the 'new' developer that Global Variables are 'bad
practice'...and the cycle continues.

This particular 'bad practice' issue is fed by the misconception that there
is other alternatives that are just as good as a Global Variable.  Not
really.  Pulling a value from a table takes a lot more time then just
pulling it from memory.  As I've just shown you, even module level variables
will lose their values with unhandled errors, so you can't even keep a
'global form' with values, unless you put them as values in a textbox.
So...values in a textbox....that's a viable option, right?  Wrong.  It's now
where near as efficient as an actual Global variable.  First of all, you
have all of the overhead of a form being opened.  Then, when getting the
value, you aren't going to a register in memory, you are going to a form,
then a control, then a property on that control.  Granted, even on 100 mhz
machines, the speed and memory issues are inconsequential, but on a larger
scale, it becomes much more apparent.  And, there are uses for global
variables that are MUCH more difficult to try and replicate with another
method.

For instance, I developed an inventory system, where all sorts of things
were done to the inventory.  If a user changes anything in the inventory, I
used a custom class, set as a global variable, which was used for ALL
transactions.  Whenever something was changed, it raised events to alert to
the various changes.  Anything that used the inventory class would
immediately refresh it's data when the event was raised.  Without having
that class as a Global Variable, to do the same type of 'live update' on
everything would have been a very daunting task.  Each new process would
have to 'trigger' every existing process, and all of the existing processes
would have to be setup to trigger the new ones.  With a Global 'class', only
the new stuff needed coding, as you would want, and all of the old stuff
just 'knew' what was happening.

Sure, I know the people that preach 'bad practices' probably won't stop, or
change their preaching, but hopefully Jim Bob the new developer will see MY
posts, and not pick up the 'bad practice' of thinking something is iffy when
it's not.

Drew

-----Original Message-----
From: Dan Waters [mailto:dwaters at usinternet.com]
Sent: Monday, May 16, 2005 2:31 PM
To: 'Access Developers discussion and problem solving'
Subject: RE: [AccessD] Global Variable


Drew,

For me, it helps a lot to understand 'why' I should follow a particular
practice.  

If I understand why, I can expand of what is being stated by applying the
'why' to my circumstance, and therefore learn even more!

Dan Waters


-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com] On Behalf Of DWUTKA at marlow.com
Sent: Monday, May 16, 2005 1:50 PM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Global Variable

You know, I think this whole debate could be avoided, again, if it was just
stated that using global variables when a 'lesser' scope should be used, is
bad practice.

I know I get into these discussions, because I am self taught, and it takes
a LOT more energy to overcome incumbent thought obstacles then it does to
learn new things.

Drew

-----Original Message-----
From: John W. Colby [mailto:jwcolby at colbyconsulting.com]
Sent: Monday, May 16, 2005 12:31 PM
To: 'Access Developers discussion and problem solving'
Subject: RE: [AccessD] Global Variable


Gustav,

There are many things generally considered poor programming practice in the
programming industry.  Excessive use of Gotos and Global variables are a
couple of examples.  In general they ARE CONSIDERED (by myself and many many
many other people) to be bad programming practices.  

Globals, like Gotos are handed down from the days of old when there was no
such thing as functions, data types declarations, scope and the many other
tools that make modern programming worlds above the code written 40 years
ago.  All of these things exist for a reason.  Globals are considered poor
programming practice because they expose variables to update and even
overwriting by code that has no business updating that variable.  

It is generally accepted practice that variables should have the minimum
exposure absolutely necessary to perform their function.  A variable used
ONLY in a specific function should NOT EVER be declared as a global
variable.  A variable used ONLY in a module should NOT EVER be declared a
global.  Microsoft and other compiler writers provide tools like variable
scope for a good reason, they help minimize, and track down bugs.  If a
variable is private to a module then if that variable is being updated
incorrectly, you at least know it is because of some code in that module.
If it can be updated anywhere in the entire program then you must search the
entire program when something goes wrong.  Function level variables
(declared inside a function) are local to the function and cannot be
declared otherwise.  

Thus the "excessive use" of globals would include making a variable,
intended for use in a module, global "just in case".  

I personally make it a practice to always explicitly declare module level
variables private 

Private MyVar as SomeVarType

unless there is an over-riding reason to expose the variable on a global
basis.  Even then I make it a practice to build a function that reads a
private variable in those cases where code in other modules must be able to
read the variable.  Only in cases where code in multiple modules must both
read and write a global variable will I expose the variable itself as a
global.  And even in those cases it is sometime useful to cause the write to
go through a function, particularly if the variable is a computed value.

Global variables is one of those issues that strikes a sensitive note with
many programmers, but it is indeed widely accepted to be poor programming
practice to just use them willy-nilly and for no good reason.  Every tool
exists for a reason and variable scope is a very powerful tool to assist the
programmer in writing better code.

John W. Colby
www.ColbyConsulting.com 

Contribute your unused CPU cycles to a good cause:
http://folding.stanford.edu/

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Gustav Brock
Sent: Monday, May 16, 2005 12:34 PM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Global Variable


Hi John

You may like or prefer or need, or not, a global variable - that's up to
everyone to decide for him/herself - but they are not "bad practice", not
even in general. You may write clumsy code using globals, but not using them
gives no guarantee for nice code.

/gustav


-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com
-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com

-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com
-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com

-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com
-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com

-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com
-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com

-- 
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com



More information about the AccessD mailing list