Lookingback, I am surprised by how many pages of literature I have assigned over the years, far more than is the norm in college philosophy classes. I never formulated a plan to do so; I never self-consciously aimed for interdisciplinarity. How did my syllabi wind up populated by so many novels, stories, poems and plays?
When Tolstoy writes philosophy, he is concerned with the transmission of morally edifying sentiments, but when he writes novels, he wants to show us evil. Even when he shows us good, he does it to show us evil. Side by side with the slow-moving disaster that is the relationship of Anna and Vronsky, Tolstoy offers us the happy, budding romance of Kitty and Levin; we watch it mature from what seemed an initially doomed courtship into an idyllic form of marriage and parenthood. But if you have read Anna Karenina, ask yourself: Could you imagine the novel with those sections removed? Now how about the other way around, with Anna deleted? To me, the first is readily imaginable, the second unthinkable. There is a reason Tolstoy did not call the work Kitty Scherbatsky.
If, in the texture of the piece, there be interwoven any scenes of satisfaction, they afford only faint gleams of pleasure, which are thrown in by way of variety, and in order to plunge the actors into deeper distress, by means of that contrast and disappointment.
There is a wonderful scene, toward the end of the novel, where we watch faithful family man Levin be drawn in by the seductive personality of the adulteress Anna. By the end of the conversation Levin comes close to jumping into her arms:
Well, most of us say, (too) many times without really understanding, "Don't use global variables", or "Singletons are evil because they are global". But what really is so bad about the ominous global state?
To elaborate, imagine you have a couple of objects that both use the same global variable. Assuming you're not using a source of randomness anywhere within either module, then the output of a particular method can be predicted (and therefore tested) if the state of the system is known before you execute the method.
However, if a method in one of the objects triggers a side effect which changes the value of the shared global state, then you no longer know what the starting state is when you execute a method in the other object. You can now no longer predict what output you'll get when you execute the method, and therefore you can't test it.
In the real world, this can have some very serious consequences. Suppose you have one class that populates a global data structure, and a different class that consumes the data in that data structure, changing its state or destroying it in the process. If the processor class executes a method before the populator class is done, the result is that the processor class will probably have incomplete data to process, and the data structure the populator class was working on could be corrupted or destroyed. Program behaviour in these circumstances becomes completely unpredictable, and will probably lead to epic lossage.
Further, global state hurts the readability of your code. If your code has an external dependency that isn't explicitly introduced into the code then whoever gets the job of maintaining your code will have to go looking for it to figure out where it came from.
As for what alternatives exist, well it's impossible to have no global state at all, but in practice it is usually possible to restrict global state to a single object that wraps all the others, and which must never be referenced by relying on the scoping rules of the language you're using. If a particular object needs a particular state, then it should explicitly ask for it by having it passed as an argument to its constructor or by a setter method. This is known as Dependency Injection.
It may seem silly to pass in a piece of state that you can already access due to the scoping rules of whatever language you're using, but the advantages are enormous. Now if someone looks at the code in isolation, it's clear what state it needs and where it's coming from. It also has huge benefits regarding the flexibility of your code module and therefore the opportunities for reusing it in different contexts. If the state is passed in and changes to the state are local to the code block, then you can pass in any state you like (if it's the correct data type) and have your code process it. Code written in this style tends to have the appearance of a collection of loosely associated components that can easily be interchanged. The code of a module shouldn't care where state comes from, just how to process it. If you pass state into a code block then that code block can exist in isolation, that isn't the case if you rely on global state.
There are plenty of other reasons why passing state around is vastly superior to relying on global state. This answer is by no means comprehensive. You could probably write an entire book on why global state is bad.
If you say "state", that is usually taken to mean "mutable state". And global mutable state is totally evil, because it means that any part of the program can influence any other part (by changing the global state).
Imagine debugging an unknown program: You find that function A behaves a certain way for certain input parameters, but sometimes it works differently for the same parameters. You find that it uses the global variable x.
It enforces the "One-and-only-one" hard rule, which, even though it couldn't possibly change, suddenly does. A whole bunch of utility code that used the globally accessible object then needs to be altered.
Having said that, most systems have some need for Big Global Objects. These are items which are large and expensive (eg Database Connection Managers), or hold pervasive state information (for example, locking information).
The problem here is that you end up with a big game of "pass-the-parcel". You have a graph of components and their dependencies, and some classes create other classes, and each have to hold a bunch of dependency components just because their spawned components (or the spawned components' components) need them.
You run into new maintenance problems. An example: Suddenly your "WidgetFactory", component deep in the graph needs a timer object that you want to mock out. However, "WidgetFactory" is created by "WidgetBuilder" which is part of "WidgetCreationManager", and you need to have three classes knowing about this timer object even though only one actually uses it. You find yourself wanting to give up and revert back to Singletons, and just make this timer object globally accessible.
Fortunately, this is exactly the problem that is solved by a Dependency Injection framework. You can simply tell the framework what classes it needs to create, and it uses reflection to figure out the dependency graph for you, and automatically constructs each object when they are needed.
You sort of answered your own question. They're difficult to manage when 'abused,' but can be useful and [somewhat] predictable when used properly, by someone who knows how to contain them. Maintenance and changes to/on the globals is usually a nightmare, made worse as the size of the application increases.
Experienced programmers who can tell the difference between globals being the only option, and them being the easy fix, can have minimal problems using them. But the endless possible issues that can arise with their use necessitates the advice against using them.
edit: To clarify what I mean, globals are unpredictable by nature. As with anything unpredictable you can take steps to contain the unpredictability, but there's always limits to what can be done. Add to this the hassle of new developers joining the project having to deal with relatively unknown variables, the recommendations against using globals should be understandable.
First of all for dependency injection to be "stateful", you would need to use singletons, so people saying this is somehow an alternative are mistaken. People use global context objects all the time... Even session state for example is in essence a global variable. Passing everything around whether by dependency injection or not isn't always the best solution. I work on a very large application currently that uses a lot of global context objects (singletons injected via an IoC container) and it has never been a problem to debug. Especially with an event driven architecture it can be preferred to use global context objects vs. passing around whatever changed. Depends who you ask.
Anything can be abused and it also depends on the type of application. Using static variables for instance in a web app is completely different than a desktop app. If you can avoid global variables, then do so, but sometimes they have their uses. At the very least make sure your global data is in a clear contextual object. As far as debugging, nothing a call stack and some breakpoints can't solve.
I want to emphasize that blindly using global variables is a bad idea. Functions should be reusable and shouldn't care where the data comes from -- referring to global variables couples the function with a specific data input. This is why it should be passed in and why dependency injection can be helpful, although you are still dealing with a centralized context store (via singletons).
Btw... Some people think dependency injection is bad, including the creator of Linq, but that isn't going to stop people from using it, including myself. Ultimately experience will be your best teacher. There are times to follow rules and times to break them.
Since some other answers here make the the distinction between mutable and immutable global state, I would like to opine that even immutable global variables/settings are often an annoyance.
If all configuration data is passed explicitly, the components become much easier to test and you never need to worry how to bootstrap a global configuration value for multiple tests, maybe even in parallel.
3a8082e126