in reply to Re: Common subs and Global Variables
in thread Common subs and Global Variables

I have used global variables in one form or another for years, and I have been constantly admonished that it is a bad thing to do. Could someone please provide a cogent argument why? I admit that it takes some care to avoid name clashes and other silly problems, but aside from such administrative considerations, what is the issue?

Replies are listed 'Best First'.
Re^3: Common subs and Global Variables
by GrandFather (Saint) on Mar 19, 2024 at 20:38 UTC

    The biggest issue is "action at a distance". That is, it is much harder to ensure correct management of global variables because the code that may affect them may be scattered through the code base. That makes it hard to think about how the various places that may alter or use a global variable interact.

    For trivial code it doesn't matter at all. But the use of global variables don't scale well as code size increases.

    A significant exception to the "don't use globals" guideline is using global constants. Because they are constant there is no issue with figuring out how their value may change (it doesn't - they are constants!). Using global constants to manage things like scaling coefficients or other magic values is vastly better than using manifest constants.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re^3: Common subs and Global Variables
by ikegami (Patriarch) on Mar 19, 2024 at 20:23 UTC

    Encapsulation, the same reason we use my variables.

    Limiting the scope of variables has a number of benefits. Primarily, that name clashes less likely, and that it's easier to find users of the variable. Don't underestimate the value of the latter; it's huge. Conversely, using variables as part of the module's interface creates a very rigid interface.

Re^3: Common subs and Global Variables (Global Variables References)
by eyepopslikeamosquito (Archbishop) on Mar 19, 2024 at 22:26 UTC

    I have used global variables in one form or another for years, and I have been constantly admonished that it is a bad thing to do. Could someone please provide a cogent argument why?

    Surprised I don't have a list of references on this topic yet. Here's a start. Other cool references welcome.

    References

    From On Coding Standards and Code Reviews:

    • Information hiding: Minimize the exposure of implementation details; provide stable interfaces to protect the remainder of the program from the details of the implementation (which are likely to change). Don't just provide full access to the data used in the implementation. Minimize the use of global data. Avoid Action at a distance.

    From On Interfaces and APIs:

    • Before lexical file handles were introduced in Perl 5.6, those evil old global file handles spawned a host of unfortunate idioms, such as: select((select($fh), $|=1)[0]). In terms of a clear and simple interface to perform a simple task (set autoflush on a file handle), it doesn't get much worse than that, a compelling illustration of why keeping state in global variables is just plain evil. Thankfully, nowadays you can replace it with: $fh->autoflush().

    👁️🍾👍🦟
Re^3: Common subs and Global Variables
by cavac (Prior) on Mar 20, 2024 at 09:50 UTC

    As code grows more complex over time (and into multiple modules), it is easy overwrite a global variable when you re-use the name by accident. And it can be hard to trace any problem, because you just can't put a debug print/stacktrace in the ONE function that is able to modify the variable.

    Sometimes a couple of global variables might be the right choice, but more often than not they are a liability.

    For me, the big exception to the rule is when i write code for microcontrollers. When you only have like 1000-4000 bytes of RAM (if you are lucky), ditching modern OO and basically laying out the memory map by hand is sometimes the best (and only) option. It's astonishing how much you can achieve with a kilobyte of memory when you spend a year shuffling bits and bytes around in your memory layout...

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
Re^3: Common subs and Global Variables
by Corion (Patriarch) on Mar 19, 2024 at 16:23 UTC

    The "administrative considerations" remind me of two quotes:

    ... but other than that, how was the play Mrs. Lincoln?
    ... but other than that, how was the parade Mrs. Kennedy?

    If you can avoid the administrative parts without needing to compromise on code functionality, why wouldn't you?

Re^3: Common subs and Global Variables
by NERDVANA (Priest) on Mar 20, 2024 at 20:37 UTC
    I want to emphasize that global *settings* are not really bad (things acting like environment), but global *variables* (meaning that they change to hold different data as the program runs) usually are.

    I will further qualify that in Perl specifically, you have the 'local' keyword which can change a global variable to affect only things within that scope, and then it goes back to its original setting at the end of that block. This pattern makes global variables much less messy than in any other language, and I use this pattern in a variety of sticky situations where normal function parameters would be awkward or inefficient.

    But, the point still remains that code like this is abjectly terrible:

    # This initializes $main::foo function_one(); # This uses the value of $main::foo and updates it function_two(); # This relies on the modified value from function_two function_three();
    Why is it so terrible? Because when the maintenance programmer comes along and tries to implement some new feature or fix some bug, they might cause function_two to not get run, and now function_three is broken. The comments I added above are typically not present, and they waste tens of hours hunting high and low through all the code to find out why it broke, and what part of their change caused it.

    Compare with:

    my $value= function_one(); function_two(\$value); function_three($value);

    Without even having any comments, you can see that $value comes from function_one, that function_two reads and maybe writes it, and that it is used by function_three. These clues dramatically speed up development and debugging. As another benefit, you can refactor this into an object where the _one, _two, _three workflow occurs during method calls. If $value is global, you can't refactor this easily, or even realize that it will be hard to refactor.

Re^3: Common subs and Global Variables
by karlgoethebier (Abbot) on Mar 20, 2024 at 17:30 UTC

    ”… what is the issue?”

    ”The principle is that a declaration in one part of the program shouldn’t drastically and invisibly alter the behavior of some other part of the program.” (Mark-Jason Dominus, Sins of Perl Revisited 1999)

    «The Crux of the Biscuit is the Apostrophe»