Why people dislike global variables so much while I find them so convenient?

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Jan 25 14:28:24 UTC 2022

On Tue, Jan 25, 2022 at 09:53:25AM +0000, rempas via Digitalmars-d wrote:
> It is known that people dislike global variables and the reason is
> that they make the code harder to debug.

The problem with global variables is that firstly, it modifies the
behaviour of a function apart from its parameters. This in itself may
not seem like a big deal, but a global variable also means it can be
modified by anyone and everyone at any time.  So you may have a call to
function F from module A, but you can't tell what the result will be,
because it depends on whether module B modified the global variable
before you called F.  Changing the order you call a pair of functions
may drastically change their behaviour in unexpected ways if they both
modify the same global variables.

In a small project this is not a big deal, but in a large project it
makes it almost impossible to debug, because how F will behave changes
depending on the entire code path leading up to the call to F (whether
anybody along that path changed the global variable and what they
changed it to).  When you're faced with a bug report, you generally
don't have enough information to tell exactly which path the code took
before it got to F, which also means you can't tell how F will behave.
When this happens not just for one function F, but for every other
function in the code where the bug is, it makes debugging an extremely
unpleasant experience.

Another problem with global variables is that there can only be *one*
instance of that global. Suppose you have a database-driven program
where basically every function needs to access the database connection.
Well, why not make it a global variable? Easy peasy.  Well, then one
day, you decide that you need to add a second database connection (maybe
for syncing, backup, or merging, whatever). Now what? ALL of your
functions assume that only a single connection exists. To add a second
connection you now have to rewrite every single function in your program
(and/or hack it by swapping the single global variable between two
connections -- very error prone and almost inevitably leads to tons of
bugs and impossible situations).  Had you written your functions to take
the database connection as a parameter, inconvenient as it may be, it
would have been a trivial code change: just pass the 2nd connection and
you're done.

> In my experience tho, it is the exact opposite. When I have a variable
> that I must pass down to 5-6 functions, I find it much easier to make
> it global rather than having it been passed in all the functions that
> need it.  This practice also makes my function signatures looking much
> cleaner.  Yeah, one variable will not make a difference but in my
> project, I have about 2-3 variables that need to be passed down to a
> lot of functions so I only think that it makes sense to use them as
> globals.

Whenever you have multiple shared parameters between a bunch of
functions, that's a sign that they probably should be member functions
of a common struct or class.  The shared parameters should be in the
struct, then you don't have to explicitly pass them around, you just add
another function to the struct and they gets passed implicitly for you.

> Another problem is the case that I'll introduce a new variable that
> needs to also be passed in most of my functions. What happens then?
> Let's say I will have 20 functions at the time. I have to change both
> the function signature and all the other places in code that call this
> function. The latter can be easily done with a quick "search and
> replace" in my text editor but still, it's a tedious thing to do.

Either group your parameters in a single struct, or make your functions
members of the struct. Then all you have to do is add another field to
your struct and you're done. No tedium.

Using a struct/class also takes care of the instancing problem: if one
day you suddenly need a different set of parameters, you just create a
different instance of your struct and everything Just Works(tm). If they
were global variables, then there can only be one instance of every
variable, and you're stuck up the creek without a paddle.


Don't drink and derive. Alcohol and algebra don't mix.

More information about the Digitalmars-d mailing list