Global Variables Are Bad

This is something I have a hard time putting in words. I've been bitten by globals in the past, so I 'know' they're 'bad', but for the life of me, I can't explain why. What I'd like is to have some straightforward "Here's why globals are bad" document I can point other people to, preferably with some concrete (if toy) examples.


As with all HeuristicRules, this is not a rule that applies 100% of the time. Code is generally clearer and easier to maintain when it does not use globals, but there are exceptions. It is similar in spirit to GotoConsideredHarmful, although use of global variables is less likely to get you branded as an inveterate hacker.

Why Global Variables Should Be Avoided When Unnecessary

Why the Convenience of Global Variables Sometimes Outweighs the Potential Problems
Example?

Even in the above cases, it's wise to consider using one of the Alternatives to Global Variables to control access to this facility. While this does help future-proof the code -- e.g. when your 'small' program grows into a very large one -- it can also simplify more immediate problems such as testing the code or making it work correctly in a concurrent environment.

Really Bad Reasons to Use Global Variables

Alternatives to Global Variables


Non-locality seems much much more convincing than any of concurrency, namespace, and memory allocation. However, the non-locality issue is much bigger than it seems. I'm thinking of situations when you come back to the code 2 weeks later, look at String important = global.getSomeImportantInfo(), and have to figure out why 'important' is getting the wrong value. Sure, non-locality describes it, but if Bob (above) asks "Why?" and Alice replies "Non-locality", I don't think Bob would learn the lesson.

Non-locality can be EssentialComplexity, which is among the reasons one might need global variables or an alternative to them (I'm fond of ContextObject and some other facilities). That you find it more or less convincing than concurrency or namespace issues mostly reflects the problems you've encountered before.


Would you consider singletons global variables? What about static variables within a namespace?

Yes and yes; though both are less obnoxious than a whole pile o' globals lying around. Static variables within a namespace are limited to that namespace (unless someone exports 'em somehow); in general when I see a static variable I look for a way to turn it into an object. Singletons are a necessary evil - in some case, there is only one of something, so providing a way of accessing it is useful. Even then, when I use singletons, I prefer to access the get_singleton() (or whatever) method rarely, and pass references to the singleton around. That way, if the singleton ever multiplies, I have less code to ReFactor.

I would not consider a singleton as a global variable unless the singleton exposed its internal variable through an accessor. Absent accessors, a singleton provides controlled access to the variable, greatly reducing the programming problems. Also, although a static variable within a namespace probably is not a global, it exhibits the same problems as a global variable within a reduced scope. Personally, I would probably replace the static variable with a singleton, just to control the access. [Note: I am using the C++ definition of static rather than the C definition.]

Agree, most of the problems stated is possible with any construct that allows the same data to be accessed globaly. Singleton is a broken solution to avoid global variables for this reason. However namespace pollution and implicit coupling does not seem to be about data, but more about identifiers - it is not much better with global functions, you almost always have to end up with some globals anyway.

[[ Perhaps I have a mental block...what's the difference between C "static" and C++ "static"? ]]

Static in C has the following uses: 1) Declare a function/variable to be at file scope - in other words, the opposite of extern. 2) Declare a variable within a function to be common to all invocations of the function, the opposite of automatic.

In ANSI C++; use 1) is deprecated and replaced with anonymous namespaces; though much C++ code still uses static in this manner (and as a result, it likely won't disappear from the language for a long time). Use 2 is still valid. C++ also adds 3) indicates that a variable class attribute (data member) is to be common to all objects of the class; and 4) indicates that a class method doesn't have a this pointer - instead, it acts like a free function rather than a member function.

For completeness, Java has uses 2-4; it does not have use 1.

Use 2 (common to both) and use 3 (C++ only) are the meanings of "static" which make sense in this context. Original poster, what was your intended meaning for the question?


I know lots of programmers who start working on a problem and their first instinct is, "I need that list in a lot of different places. No problem, we'll just add a global variable... et voila!". When the number of globals starts to get unmanageable, they sometimes put all the globals into one big global list of globals.

Problem: Adding globals is really easy. It's easy to get in the habit of declaring them. It is much faster than thinking of a good design.

Compounded: In some simple circumstances, it really is the simplest thing to do.

Even worse: Once you have a global variable, it's much harder to get rid of it as time goes on.

Question: How does a programmer learn to avoid this temptation except in the simplest of cases?

For experienced programmers, there is little temptation. Using a local or the SingletonPattern is usually easy, even if it does take a few extra seconds to type. After you get burned a couple of times, you will forget the notion that globals would make things easier.

But SingletonsAreEvil. But besides that contentious fact, could you give a toy example of how using a local or parameter would be fairly easy (remember, the list is being used 'in a lot of different places').

Perhaps SingletonsAreEvil, but SingletonsAreBetterThanGlobals?. Wouldn't that mean that GlobalVariablesAreBad is an understatement?

A toy example is unlikely to demonstrate any problem with globals. How about we start with you giving a real example of code that you think is simplest with globals, and then somebody can show equivalent global-less code?

I currently don't have any real examples, since I avoid globals like the plague, and any examples I may have come across in the past are not mine to publish (and would take up lots of space anyway).

Well, here's a toy example, which I'm sure will convince nobody. Say you have to write a program that reads a bunch of strings from files and then does things with that list of strings. Here's the globals-are-simplest approach:

 list<string> myList;  // global

void read_strings() { /* read strings into myList */ } void print_strings() { /* write contents of myList to stdout */ } void sort_strings() { /* sort contents of myList */ } void sort_strings_reverse() { /* reverse-sort contents of myList */ } void unique_strings() { /* remove duplicate strings */ }

int main() { read_strings(); sort_strings(); print_strings(); sort_strings_reverse(); print_strings(); unique_strings(); print_strings(); return 0; }

Here's the globals-are-unnecessary approach:

 class String_List
 {
 private:
list<string> m_List;  // member
 public:
void read_strings() { /* read strings into m_List */ }
void print_strings() { /* write contents of m_List to stdout */ }
void sort_strings() { /* sort contents of m_List */ }
void sort_strings_reverse() { /* reverse-sort contents of m_List */ }
void unique_strings() { /* remove duplicate strings */ }
 };

int main() { String_List myList; // local myList.read_strings(); myList.sort_strings(); myList.print_strings(); myList.sort_strings_reverse(); myList.print_strings(); myList.unique_strings(); myList.print_strings(); return 0; }

Which is better? I think the global-less one is better, but if anyone disagrees, I can't explain it to them.

Any time you find that you need a particular thing in 'a lot of different places', chances are that all those places are conceptually related, and so you can create a class, a namespace, a function, or some other higher-level organizational unit to represent that relationship. This makes the program easier to understand.

Well this is a very limited example, and perhaps in this case (if you're never going to reuse the code) the globals are not bad. However if you're ever planning on extending the software, you'll have to start moving things around. And it's handier to have a class to move around, than a set of functions. Also if you ever change the structure of m_list, it's easier to look up which methods (just look in the same class) than go through all the sources to see if anyone else besides the -intended- functions are using that structure. -- ChristophePoucet?

For non-globality to be useful, it has to allow extendability or give some other benefit. For programs that won't be extended, globals are fine. Allow me to rewrite the toy example to be extendable and replaceble. There are probably syntaxic errors.

 class String_List
 {
 public:
list<string> m_List;  // member
 }

class String_List_Manager { private: list<string> m_List; // member public: String_List_Manager ( String_List m_List ) { this.m_List = m_List; } void read_strings() { /* read strings into m_List */ } void print_strings() { /* write contents of m_List to stdout */ } void sort_strings() { /* sort contents of m_List */ } void sort_strings_reverse() { /* reverse-sort contents of m_List */ } void unique_strings() { /* remove duplicate strings */ } };

int main() { String_List myList; // local String_ListManager myListManager = new myListManager(myList); // local myListManager.read_strings(); myListManager.sort_strings(); myListManager.print_strings(); myListManager.sort_strings_reverse(); myListManager.print_strings(); myListManager.unique_strings(); myListManager.print_strings(); return 0; }

This way it is very easy to replace the list with new list for debugging purposes, or replacing the methods without replacing the list, when you want different results. You only have to replace the content of the local variables. Other parts of the program using the String_List class are unaffected, because they are still invoking the old classes in their own local variables.

////String_List myList;  // local
////String_ListManager myListManager = new myListManager(myList);  // local

String_List myListTestValues; // local String_ListManagerPerfected myListManager = new myListManagerPerfected(myList); // local

At some point on the future, if the program gets more and more extended, the code may become this.

String_List myList;  // local

if( condition("avaluators" ) myList = listFactory.getAvaluatorList(); // filled from a file else if ( condition("teachers") myList = listFactory.getTeacherList();// filled from a file else if ( condition("pupils") myList = listFactory.getPupilList();// filled from a file else if ( condition("DB" ) myList = listFactory.getList(myDB);// pull data from DB else if ( condition("again") myList = formerList;// passed by argument elsemyList = listFactory.defaultList; // hardcoded inside the class

//rest of code is not modified at all String_ListManager myListManager = new myListManager(myList); // local etc...

Of course, listFactory is global, so you ought to start the de-globalizing process all over the same again, because you hace created new globals somewhere to deal with the new extensions. I have found that at any random point of the program, I always need/have some global variable or other. I just try reducing them to the minim. For this example, probably listFactory can be left as global. I would only convert it to local if I foresaw some need for n different List_Factory methods in the future. -- Enric Naval October 2005


Basic OO Concept - Cohesive Methods

One of the major arguments against global variables is that they defy the basic OO concept of cohesive methods. With a global variable all of the accesses and operations on the variable are scattered around the code. By pulling all of the methods into a single class or module, they can be evaluated and maintained as a unit.

Pervasive use of accessors for loading and storing at least moves problems from "state" space into "behavior" space, where they can be addressed more straightforwardly. Mechanisms for limiting the visibility of methods are more mature and are more effectively supported by various language alternatives.


You're RefactoringLegacyCode, you see a global, you want to get rid of it. How do you do this? What are the steps?

Exactly what to do depends on how the global is used. The first step is to find all uses of the global throughout the code, and get a feel for what the significance of the variable is and how it relates to the rest of the program. Pay particular attention to the "lifetime" of the variable (when it gets initialized, when it is first used, when it is last used, how it gets cleaned up). Then, you will probably make the global a data member of a class (for OO languages), or you will write some get/set functions. Converting to the SingletonPattern is common, but you may discover that it makes more sense for the data element to be a member of an existing singleton, or maybe even an instance variable.

The following steps work for me.

  1. Create a basic read method, either as a class or a global function. Replace all reads with the access method, but leave the variable defined as a global.
  2. Review each of the writes to the method and extract action functions one at a time. Unless two operations are coded identically in the original code, extract each write access separately.
  3. Change the variable scope from global to local.
  4. Analyze similar action functions to determine if any can be merged, i.e., there are no functional differences in the results of the function, just differences in the implementation details.
  5. Review the calls to the read method and see if a more complex functionality should be applied. Follow the approach for writes and unless implementations are identical, create separate access functions.
  6. Analyze the access functions for duplication.

Ah, it's step #2 which I was missing.


A discussion about whether databases are depositories of "global variables" or not is under DatabaseNotMoreGlobalThanClasses.

An interesting idea for consideration is what if the database stored the current object, i.e., data and code instead of just the data? Difficulties include multiple language use and disk and memory size on the database.


See the article "Global Variables Considered Harmful" by W.A. Wulf, M. Shaw. GlobalVariablesConsideredHarmful

EditHint: Consider moving all the text at GlobalVariablesAreBad to GlobalVariablesConsideredHarmful, leaving only a pointer to GlobalVariablesConsideredHarmful .

Or not: GlobalVariablesConsideredHarmful discusses a paper that objects to global variables on the grounds that "LexicalScoping is bad" -- which is a highly dubious argument, best separated from the arguments made on this page. In the ObjectCapabilityModel, LexicalScoping is considered good, but global variables are to be avoided at all costs.


Forced Categorization?

A good example of a global variable is LoginId? (or NetworkId?) whereby the app is making a lot of security or role-based calls and must pass this all over the place nearly everywhere. Also constants and enums make for a lot of good global variables. Things like colors and their hex values, provided they are used almost everywhere.

Disagree: 1) constants/enums are constant, not variables, 2) they still often are better defined in a scope or namespace (such as color::red) if for no other reason than to avoid name collisions.

Login-ID is not a constant in a language sense. The program likely will need to change it at run-time (near start-up). And even colors can change at run-time because some browsers render them slightly wrong when one is trying to match GIFs.

Another problem with grouping them is "changing responsibilities". For example, you may associate something with a "security" name-space or object, but later decide to move it to a "user" name-space/object because it is a better fit there. If you group stuff, you may have to visit each usage to change the grouping. If it is simply a global variable, then you don't have to change anything; it just gets a different value.

A variable "user_is_a_newbie" will always be a valid variable to reference. It is Popeye-style K.I.S.S.: "I yam what I yam and nothing else". But if we start out with "security.user_is_a_newbie" (or security::user_is_a_newbie) and later change it to "user.user_is_a_newbie", then we have to visit and change each usage.

Perhaps this is related to ResponsibilityDrivenDesignConflictsWithYagni. I am not saying that grouping them into the likes of "user", "security", "environment" structures/objects is summarily bad, but it does have its downsides in that something may belong to multiple or none or need to change between them. Packaging them forces you to choose categories, and the cost of putting it in the inappropriate category or changing it later is fairly large. The lines between categories such as "user", "security", and "environment" are blurred and situational.

Thus, I won't complain if somebody leaves those kinds of things in old-fashioned global variables. The trade-offs don't decisively favor grouping over non-grouping. The scale does not tip heavily any one way.

A compromise may be to make them global function calls. Or perhaps methods of a class called "app_environ", a kind of catch-all dumping ground for such critters. These offer enough indirection for future change handling, but not too much premature "forced" abstraction.


It seems to me that it's impossible to avoid global variables altogether. Even if you have no explicit globals and no singletons, the types themselves are global, are they not? As are the highest-level namespaces. If Service.instance() is a disguised global, isn't it because Service is itself a global? I just took a look at YouCantEncapsulateEverything, which seems to come to a similar conclusion. I'd go a bit further and say that even if the class in question were not a singleton, the statement "new Service()" would refer to the global Service. Of course, the arguments here for minimizing globals apply nonetheless. -- ThomSmith?

The arguments here are for minimising global variables. Types, namespaces, and classes are not variables.

And yet, when you have class variables, this attempt to distinguish classes (and things that contain classes) from global variables starts failing, though of course complexities remain. However, as for the the underlying concept, that classes are not variable:

The distinction perhaps depends on the language.

Please explain?

[For some languages (like Ruby and Smalltalk) types and classes are mutable objects and, therefore, variable. Consider MetaObjectProtocol. Namespaces may be variable, too, as in Scheme where the environment is reified.]

True, but that's not what ThomSmith? or Top meant, is it?

[I cannot attest to what was meant, only what was said. The distinction does depend on the language. That said, Thom is incorrect. It is not "impossible" to avoid global variables, or even to avoid global references of all sorts. ObjectCapabilityLanguages are designed around avoiding global references as a powerful security mechanism, and adherence to the principles eliminate the possibility of SingletonPattern (of which 'Service.instance()' seems to be an example) being introduced within the code itself. ContextObject containing object references to things outside the 'program' eliminates the need for Singletons, and design for threading of ContextObject can easily be added to the language (DynamicScoping or ExplicitManagementOfImplicitContext). A function like 'Service.instance()' that always returns the same instance for some type 'Service' may be impossible to write.]

I should have said global references, rather than global variables, which makes the issue a bit different from what's discussed on this page. I meant to include the possibilities of types that are not first-class values, such as in Java. I'm not familiar with ObjectCapabilityLanguage, so I can't comment on them. Lacking such knowledge, I was referring to more conventional languages. Of course, when you're talking about something like Java types, many of the disadvantages of global references are not applicable to begin with. -- ThomSmith?

['static' variables for classes, and access to the OS via 'System', and access to implicit channels via 'print' or 'current time' and such, would certainly qualify as global references. I agree that it is hard to avoid these things in 'conventional languages', which is in part why conventional languages are not particularly secure - they provide very little confinement internally, so one has EggShellSecurity?: one breach and everything's rotten.]


See GlobalVariablesConsideredHarmful, SingletonsAreEvil, SingletonGlobalProblems, GlobalVariable


Just found this in a discussion thread on stack overflow: global variables aren't bad per se. What's bad is globally accessible mutable state. I don't know yet if I should believe this or not, but it sort of rings a bell. -- flj


For Definition, Comparison and Contrast, See:


CategoryScope


Directions! In my view whenever a consumer requires to reference a global variable, it means "it" has a dependency on the global set (singleton / context obj) which means the consumer demands something from the higher layer (lets face it globals are mostly in the app layer)... LawOfDemeter really keeps the code clean here - we provide all the info to the consumer. Sometimes the global variables do provide the simplest / fastest solution but we should watch out for their pollution into the other layers.

-- RishikeshParkhe


EditText of this page (last edited July 31, 2013) or FindPage with title or text search