So I can read from a global variable
def f() :
print x
And I can also assign it
def g()
global x
x = 3
When people say "global variables are bad", do they mean that both reading and assigning are bad, or just assigning is bad? (my impression is that reading is not dangerous)
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:
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, inSystem.IO
, gives you the ability to print to the terminal (stdout) or to a file, just like you might expect. The other, inSystem.Printers
, tries to connect to the system's default printer and physically print out the line on paper. So if I write:What do I mean? Should it print to the screen or to paper? But using namespaces:
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: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 theSystem.IO
namespace with the namespace of my file[1].How about using both? Most languages would do:
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:
Will end in something like.
Whereas you might expected
So I'd say both variants are little dangerous.
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:
That is,
frob()
s behavior depends on state whos nature is not obvious from either the body offrob()
, nor from any code that might have called it. You have to try to figure out what changesmy_global
, and when those changes happen in relation to whenfrob()
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.