So I can read from a global variable
def f() :
print x
And I can also assign it
def g()
global x
x = 3
The problem is not so much "global == bad" so much as "Global mutable state makes it hard to reason about program flow"
To illustrate, imagine this function:
def frob():
if my_global:
wibble()
else:
wobble()
That is, frob()
s behavior depends on state whos nature is not obvious from either the body of frob()
, nor from any code that might have called it. You have to try to figure out what changes my_global
, and when those changes happen in relation to when frob()
is called.
When programming small scripts, this isn't much of a problem, you can see and understand all of the places that the global variable changes, and probably sort out in your head when it changes and when the dependent bits are invoked. In large programs, that's much more effort, to the point that global mutable state is widely regarded as an anti-pattern.
In all programming languages, we have this concept called scope. The scope of a variable is, to put it very simply, the areas where that variable is accessible in the source code.
Imagine for a moment we didn't have this. Have you ever tried to sign up for an account on a website or game with millions of users that requires unique usernames? Did you go through three or four of them before you found one that worked? Did you end up with something that didn't resemble what you originally wanted, and instead had useless information tacked on the end of it (username_2014_1234
)?
Now suppose no programming languages had scope. You would go through this every time you had to name a variable! Even within your own program, you could not do something like this:
x = 5;
function add_6_to_x(x) {
return x + 6;
}
With proper scope (giving variables within functions their own local scope), this works, because x
refers to something different in both places. Without it, there is a name collision that must be resolved either by the compiler or, more likely, the poor programmer who can't just name a variable and get along with his life.
Some programming languages have gone beyond simple scope and introduced namespaces. Namespaces can act in one of two ways (or even both!). One thing they allow is qualified naming schemes. Qualified names resolve name collisions by giving names a prefix to denote where they come from. Suppose there was a programming language (there's not) that had two println
functions. The first, in System.IO
, gives you the ability to print to the terminal (stdout) or to a file, just like you might expect. The other, in System.Printers
, tries to connect to the system's default printer and physically print out the line on paper. So if I write:
println("The quick brown fox jumped over the lazy dog.");
What do I mean? Should it print to the screen or to paper? But using namespaces:
using System;
System.IO.println("The quick brown fox jumped over the lazy dog.");
it is now perfectly clear. Now wait, you might say: what has this really gained me? After all, I have to do more typing. The gain here is that we can have two totally different functions, provided by two separate packages, with the same name. Think about that for a second: can you imagine if every time you wrote code for a specific language you had to scour the web to see if anyone had defined that function name before? Terrible!
The other thing namespaces do is allow flexibility. What if I don't want to write System.IO.println
? That's fine as long as I'm only going to be using one. Most languages solve that like this:
using System.IO;
println("The quick brown fox jumped over the lazy dog.");
I can just put one namespace qualification at the top of my file, and I can call println
all day long without qualifications. Basically, it merges the System.IO
namespace with the namespace of my file[1].
How about using both? Most languages would do:
using System.IO.println;
using System.Printers.println as print_out;
Now they have their own separate (short, user-defined) names. Great!
Obviously, this gives developers a lot of power and flexibility, and takes care of the problem that developers all over the world can, and very probably will, come up with the same names for things, even if they're contextually completely different things. In fact, that's all either scope or namespacing is: a context for which identifiers are valid, and what they refer to.
Anything not in such a context is global. Sometimes global variables can seem useful, because they are available in places that a normal variable wouldn't be. For new programmers, this is often tempting because you can access a variable simply by making it global if you didn't know how to get to it otherwise.
But global names violate all of the above arrangements by ignoring the usual rules of scope and namespacing (because global means they exist in every scope and namespace). If everyone simply made all of their variables global, we would be right back in the terrible world of myVar_2014_1234
, and probably a lot of things would stop working.
So when people say, "global names are bad", or act like you just resurrected Hitler because you used one, it's not because they're not useful. It's because they like our nice world of neatly contained scopes and namespaces (after all, they're in every modern programming language for a reason!), and you're violating that agreement. It's the same reason people don't like it when you throw trash in the street: if everyone did it, the world would be an ugly, messy, unliveable place. Please don't abuse global names. :)
[1]: This is nearly the same thing as scope, but we usually don't call it that.
Global variables can be changed and access from nearly everywhere. This includes maybe colliding namespace and assignments,where you don't want to have them.
To give an example:
def someFunction():
global myVar
myVar = "fuuu"
print myVar
myVar = "baa"
f()
print myVar
Will end in something like.
fuuu
fuuu
Whereas you might expected
fuuu
baa
So I'd say both variants are little dangerous.