Fog Creek Software
Discussion Board




Global Variable Subtlety

I've read many times that global variables are bad in any programming environment.  I can see the argument for simple types since there can be no stateful inspection, however an Object is pretty much it's own program.

Is that right?

Wayne
Sunday, May 11, 2003

One problem with a global variable is that to know who is reading/writing it you must know the entire program. On the other hand, the "singleton pattern" is usually global.

Christopher Wells
Sunday, May 11, 2003

Rule #1: Global Variables are bad. They are evil. They are the worst idea you could ever have.

Rule #2: You *will* have them in you software. #1, like many political and philosophical ideals, is really only applicable in an academic environment.

Really, most things that people make "global" shouldn't be. But there are cases where they make sense and you shouldn't avoid them purely on principal.

Like someone else said, a singleton is typically global and there are plenty of reasons to employ a singleton. Just take each case as they come. Be weary, but don't be afraid to use them.

Marc
Monday, May 12, 2003

I'm not quite sure what the question is here. Are you asking why you should avoid globals in general, or are you asking if objects as globals are acceptable due to encapsulation?

If the latter, having an object as a global is still a bad idea. Having globals limits reuse, because any code you try and reuse will have to bring the global along with it, which means you need to FIND the darn thing.

Globals also limit thread safety. Just because your code is single threaded now doesn't mean that it won't be multithreaded in the future.

Globals limit integration, since you have more potential for name clashes with other variables in your program. Granted, with C++ namespaces, that's not as big a deal as it once was.

In C++, you have the initialization order of global variables to worry about.

Singletons avoid many of these problems, but not all. And they have their own problems. Globals are still bad, object or not.

Chris Tavares
Monday, May 12, 2003

Globabl Variables are inevitable - a program must always have globabl variables.

When it is said that global variables are bad, it is not so much the existance of global variables but rather what they are used for.

Globabl variables are a bit like root access in unix - they are very powerful and easily abused.

Should unix systems have root - of course they should.  Should users log on as root?  Thats just asking for trouble.

The issue is not that you should never use a global variable.  The issue is that a variable should be given the most restrictive scope possible.  This makes that variable easier to manage.

However, sometimes it makes sense for that scope to be global.  In Java, for example, the System variable is global and every time you use System.out.println() you are using it.

Ged Byrne
Monday, May 12, 2003

All points above accepted, although I would add a couple of examples.

Programmer 1 has used globals,

Global DateofBirth as Date
Global CurrentDate as Date

Function Age()
'Some algorythm using globals
End Function


Programmer 2 has correctly not used globals

Function Age( DateOfBirth as Date, CurrentDate as Date)
  ' Some algorithm
End Function.



No consider the differences

1 is harder to use ; you need to jknow the name of the variables and set them first.

1 can producve errors.  Two routines running concurrently would trash each other.

1 is stateful.  It also takes more memory because the variables exist all the time, not when they are being used.

1 is high maintenance.  If I want to reuse this code, I also need to copy global variables across. 

1 may have other bugs that are not obvious;  Other routines may reuse the gobal variables, so that when you set the current date for example, and several lines later attempt to use the routine, the wrong answer is produced.  Another way of stateing this is that 2 is easy to verify the algorythm.  1 cannot be easily verified as correct.



2 is the reverse of all the above!

Fergus Allan
Monday, May 12, 2003

Nice example.  I can add a few more "why's" the the list:

. Example 1 requires locking to be thread-safe, example 2 is inherently thread-safe.

. If you require more than one instance of a structure carrying fields CurrentDate and DateOfBirth, example 1 has to be rewritten.  Example 2 works as is.

Often, you will need one global in an application, library or module.  One and only one "root of all evil" global structure which you use for instance management of the thing you're doing.

const "globals" don't count - their state is static.

Nat Ersoz
Monday, May 12, 2003

I can see there is a lot to consider here, thanks for your help.

Wayne
Monday, May 12, 2003


It also depends of the scope (no pun) of the project. YMMV.

Leonardo Herrera
Monday, May 12, 2003

When you say "global" in the realm of classes, do you mean global to the class (class-level variable)? That's not a global in the same sense as the procedural world.

As long as you encapsulate access to a variable within a class, the entire class can have access to it, and it's not a big deal. Obviously, it's better to restrict scope when you can.

jason

JasonB
Monday, May 12, 2003

I do not think there is a single truly global variable (except for constants) in my current app, which is pretty large.
The exception, sort of, singletons which construct themselves when first needed.

Global Variables are said to be bad for all the reasons given previous, they are hard to debug, they make functions have hidden dependencies (the function definition doesn't tell you what it does, without reading it's entire source), they make it impossible to easily extract and re-use some code.

Also, nobody said it, but most programs spend more time in maintenance, and programs with many global variables are usually MUCH harder to maintain and debug, as you can't easily see what depends on what, what changes the variable. hidden side effects etc.  Example in a moment.

One nasty thing that often arises with global variables is the way they are used - namely you only get 1 copy to share around (which is maintenance nightmare).  For example, suppose there is some global containing the last status from a database library (not a great example but illustrates the point).

// in reports generation
DatabaseLibrary1() ;
BusinessProcessLibrary1() ;
if (global_DatabaseLibraryStatus == ... etc...)

This code works fine. Now somebody modifies the Business Process Library to look up the tax rates from a database instead of hard-coding them. Great improvement... except because of the BusinessLibrary1() function calls the database, this modifies the database global status variable, breaking the reports code above!

- in this case instead of a global, some kind of return from the functions indicating the status would be better

status = DatabaseLibrary1() ;
BusinessProcessLibrary1() ;
if (status == ... etc...)



Generally if you use a global, the best idea is to make it the least-global permissible...  This doesn't remove all problems... but might help some

For example: a module level global (not visible to other modules) is probably less risky, than some global available to the entire program.


Now to switch tacks

Very occassionally globals can be good. (with provisos about data hiding as much as possible)

If you know100% there is only 1 copy of something, then it *might* be faster to access that 1 copy, rather than pass around pointers to that item to lots of funtions.  For most apps, this is not a valid reason (e.g. a database program is probably I/O bound, and CPU speed is not an issue), but for some apps it might be.

If the variable basically does need to be seen by every single function (usually short programs), particulary if set up early and just read later, a global might be a reasonable clean code-wise solution (singletons if availabe in your language might be better than just a whole bunch of globals)

If you are in maintenance mode, and 2 functions at opposite ends of the program interact to cause some problem that you need to fix.  If you track down this kind of bug, your only option might be to allow these 2 functions to communicate somehow.  If you don't have the option of redesigning the interfaces of all the intermediate functions, a global variable to communicate between them, might be the least bad alternative.

S Tanna
Monday, May 12, 2003

Beware that a singelton object is not a guarantee that it will not contain any of the drawbacks of the global.

I have seen a singelton object with an Items collection property attached to it. That's no different than a Public Items As New Collection.

Oh, how this property was abused!

Thomas Eyde
Tuesday, May 13, 2003

Globals can be useful, they can be managed as a  class such as theApp which contains all the the singleton settings for the whole app.  The object is created at the time the application is initialised and destroyed and only ref counted, no private creations allowed.

Simon Lucy
Tuesday, May 13, 2003

Slightly off topic, but on at least two separate occasions I've come across code where somebody created a global class called theApp which is referred to all over the place in a big mess ... their justification being "MFC does it".

I'd agree there are cases whereby the solution that doesn't use global variables is more boilerplate and cumbersome than one that does. For example, suppose you have a hierarchy of objects, with each one using some other object that's common to everything. Without using globals you'd have to pass references of the common object around. If you can do it, great, but I've found it gets tedious to have to do it to more than two objects, at which point bugs creep in due to boredom.

On the other hand, I'd try and restrict its use as best possible (such that anyone can get a readonly reference to a global object, but nobody can write to it).

Better than being unemployed...
Tuesday, May 13, 2003

"If you are in maintenance mode, and 2 functions at opposite ends of the program interact to cause some problem that you need to fix.  If you track down this kind of bug, your only option might be to allow these 2 functions to communicate somehow"

If functions are interacting, then they're already communicating. You want to figure out how they're interacting and fix that before adding yet another interaction that's probably just going to be masking the original problem. Oddly enough, this essentially means shared data already exists - and global variables are shared data with the widest scope possible.

If it's "sensible" interaction where they're modifying data that needs to be shared, then adding extra control data to manage the communication may make perfect sense, as the change will be safer than just adding a random extra global variable, especially if the shared data wasn't global to start with.

If the interaction is subtle and hard to find, then it's even more important that you find it, because there's no way to tell what else it's doing if you don't even know what it is.

In general, data that's shared far and wide makes me nervous, because the more accessible it is, the more different places in the program can cause subtle and hard to find problems.

andrew m
Wednesday, May 14, 2003

I would respectfully disagree that 2 functions which interact must necessarily communicate, at least sort of.

The problem is an external resource (external network, database, GUI library, hardware etc etc) or library code may maintain a hidden state. For example, after function A does X thru this external resource, and B attempts Y thru the external resource.  If A occurs before B, Y works in a certain way, if B occurs before A, Y works in a different way... or more complicated variations :-)

Now the ideal answer might be to fix the external resource, but you don't necessarily have control over it or it's problems or versions... or you might prefer not to use anything you can't control, in which case you are limited in what kinds of apps you can develop.  Assuming neither of these apply, you have to work within the limitations of whatever the item is, and if necessary work round it's limitations.

So you are stuck with spreading data far and wide.  You could wrap the global variable in a function or singleton so it acts like a global without being syntactically an actual global variable... but it's still ugly, just ugly with marginally nicer wrapping paper.

It's never desirable, but sometimes something like this might be your only practical choice.

And one last point... before doing something like this, I would want to be double 110% sure that this work-round was actually addressing whatever the underlying issue was, not merely masking some different or deeper issue.

S Tanna
Wednesday, May 14, 2003

An example where global variable can not be avoided:

1) you write package A.

2) you downloaded a tool B written by some unknown person.

3) B helps you by generating classes which you are allowed to insert statements at various locations in the output.
You have no control of how the code is generated. You don't know how many classes there are. You don't know which object calls which. Worse still, there is no parameter passing when contructing B's entry point object.

4) Your inserted code for B needs to access a local variable C in A.

5) You must use B and can not rewrite B.

Choy Man Hoi
Friday, August 13, 2004

*  Recent Topics

*  Fog Creek Home