Alternative to global variables/constants - c++

I keep reading that using global variables is bad programming design, but does that mean global constants are also bad?
What alternatives are there instead of global variables/constants and what's the best way to declare constants that's needed in multiple source files ?

The primary reason behind global variables being bad is reliance of shared state, which makes it easy for different parts of a program to cause unanticipated interference with other parts of the program by manipulating the shared state in ways that you did not intend to, making the program more error prone, hard to debug, and hard to maintain.
Constants, on the other hand, are pretty much okay, except for the fact that they pollute the global namespace (which might cause unintended consequences at compile time by changing the meaning of a symbol in the compilation unit). If you can declare them in a specific namespace/scope, then you're going to be fine.

The real problem with global variables is that they encourage change from many points in the code. Functions that do something also have the side effect of changing global state (in fact, Functional Programming does not allow side effects at all to avoid this pitfall).
That programming style is hard to properly debug and maintain.
Keep data close to where it is used so that there is a well-defined mechanism to alter it.
Global constants do not suffer from the same issue.

Global variables lead to practical problems from large (often unknown) amounts of code relying on shared state. This can (does) lead to interactions that are hard to understand, trace, etc. In short, lots of code ends up tightly coupled, which will often lead to problems.
Global constants are mostly a (potential) philosophical problem. Since they are constant, most of the real problems from global variables never arise. At the same time, it's perfectly reasonable to question whether a particular constant really should be global or not. If (for example) you were dealing with physics, defining the speed of light as a global constant might make sense. Depending on the field, things like Pi, e, etc., can make sense as globals as well. On the other hand, if you can reasonably restrict the need for such things to less code, that's generally preferable. The value of Pi isn't going to change, but something like
x = area(some_circle);
tends to be more readable/understandable than:
x = some_circle.radius * some_circle.radius * Pi;

Related

Is it OK to use global-scope objects (structs) in C++ (C)?

As we all know, it is a bad habit to use global variables unnecessarily and there is a tendency to keep the scope as small as possible.
But what about objects? Or structure instantiations of a similar function in C. Is there anything wrong with using global objects across multiple source files?
Thanks for sheding some light to this issue as I just got a bit... mangled.
summary
Global scalar type variables are a tool and tools are not good or bad, their use is appropriate or inappropriate. Adding the power of classes to that tool is not good or bad, it has the potential to improve the appropriateness or deteriorate the appropriateness.
Objects
An answer requires a definition of object. Object is not the complement of variable. The complement of variable is constant. I will use "scalar types" as the complement of object.
The problems of using global scalar type variables
It seems that the problems of global variables are in general something along
non-locality
no constraint checking
coupling
concurrency problems
namespace pollution
testing and debugging
I think as long as we talk about scalar types memory footprint is an argument to be considered obsolete at least for PCs, embedded might be a different thing.
On remark: constants do not have all of this problems, thats why global constants are far more common than global variables.
The problems of using global objects
You have to ask yourself whether any of this problems is eliminated by using objects instead of scalar type variables
All of those problems apply to objects as well.
Plus they add all the complexities of classes on top and make every single of those objections worse, at least in general.
With objects you just have more locations to break everything, just some locations more that hinder debugging by side effects. Objects have the tendency to become a little bit more complex, adding to potential consistent initialization problems.
With objects you suddenly not only have to manage access or not, but you have to make sure that every single point of access is compatible to the current interface of your object and the constraints of the underlying data type. Make sure that parts of the program manage ownership correctly.
I think it is not a matter of opinion: If you consider global scalar type variables to be bad you will have to consider global objects to be bad a fortiori.
cum grano salis
Of course there are rightful and perfectly justified applications of global scalar type variables as well as of global objects.
And if several global variables are logically connected I think bundling those connections in a global object might tackle some of the objections. E.g. namespace pollution is of course reduced when you move some global scalar type variables in an object. And if there is a invariant in these variables of course the class of a global object is the first place you would be looking for that and a class would definitely the best place to code that invariant. Setters might be a tool to soothe the problem of missing constraints.

What is the need of global objects in c++?

I know that C++ also allows to create global objects of class and struct.
#include <iostream>
using std::cout;
class Test
{
public:
void fun()
{
cout<<"a= "<<a;
}
private:
int a=9;
};
Test t; // global object
int main()
{
t.fun();
return 0;
}
When & where should i use global objects? Is there any specific use of global objects? Please help me.
The short answer is there is no need.
The long answer is that it can sometimes be convenient. Unfortunately convenience is subjective, and what one finds to convenient another might find to be too lenient.
Global objects have issues (among which muddying data flows in the code and access synchronization), but sometimes one might find it convenient nonetheless to use one because it makes something easier. It can indeed remain easier, or it can prove a maintenance burden, but that only the future can tell...
... If you can avoid global objects, in general you should be better off. In practice, though, you will rarely encounter issues before programming at scale; for toy examples and students' projects there is rarely an issue, which is why beginners fail to understand why more seasoned developers avoid them like the plague.
In a complex project, you shouldn't. You should always be within a namespace if you plan to use you're assembly in other projects.
An example of something that might be that high in scope is an operator overload or an interface that you define which will be used many times.
Good practice...organize your project to use descriptive and intuitive namespaces.
Global is really only useful in simple project that simple don't use namespaces.
The question is malposed: is there a need for if wile and do, since we can do all with just for ?
The technical answer is "no, there is no need: the fact we can do without proves it". But a little more pragmatism show us that reducing every control flow into a single keywork makes code harder to track and follow. So it is technically possible but not always convenient.
Now: can we do without global objects?
A first non-answer is "yes, with singletons". But a singleton is a static object obtained through a function. They are not that conceptually different if not for a design flaw (known as "static initialization order fiasco") due to C++ not specifying global initialization object order essentially to allow multiple translation unit to coexist in a same linked executable. Singleton allow to circumvent that problem, but are essentially a workaround to allow global "things" to exist.
The existence of that flaw (and the singleton technique) is wat makes many "teachers" to draw some "moral" suasion like "never use global objects, or the flame of hell will burn your ass-hair". But that soon do std::cout << "hello world" and immediately loose ALL their credibility.
The point is that without "globals" everything is "scope local" and there is no "dynamic scope" in C++: if funcA calls funcB, funcB cannot see funcA locals, hence the only way to access things across scopes is parameter passing of reference or pointers.
In context which are mostly "functional", the missing of "dynamic scopes" is compensated by "lamba captures", and everything else will go as paramenter.
In context which are mostly "procedural", the need of a "state" that survives scopes and can be modified while going in and out is more suited for global objects. And that's the reason cout is that. It represent a resource theat pre-exist and post-exist the program, whose state evolves across various calls. If there is no global way to access cout, it should be initialized in main, an passed as a reference parameter to whatever function call: even the one that have no output to give, since they may call themselves something else that has output to give.
In fact you can think to global object as "implicit parameters passed to every function".
You can warp in global functions but -if functions themselves can be objects and object themselves can be functional- why saying global objects are bad and global functions can be right?
The actual only reason, in fact, turns out to be the static initialization order fiasco
I would say that global variables are needed for backwards compatibility with c. That is for sure, and this is the only hard reason I see. Since classes and structs are essentially the same, it probably didn't make much sense in forbidding only one.
I don't know any patterns or use-cases that are universally accepted as a good practice, that would make use of global objects. Usually global objects, sooner or later, lead to mess if not interacted with properly. They hide data flow and relationships. It is extremely easily to trip over it.
Still, I have seen some libraries exposing some objects as globals. Usually things that contain some static data. But there are other cases too, notable example being standard library's std::cout and family.
I won't judge if it's good or bad approach. This is too subjective IMO. You could probably use singletons, but one might argue, you can work on a global object under a contract etc. etc.

When are global variables actually considered good/recommended practice?

I've been reading a lot about why global variables are bad and why they should not be used. And yet most of the commonly used programming languages support globals in some way.
So my question is what is the reason global variables are still needed, do they offer some unique and irreplaceable advantage that cannot be implemented alternatively? Are there any benefits to global addressing compared to user specified custom indirection to retrieve an object out of its local scope?
As far as I understand, in modern programming languages, global addressing comes with the same performance penalty as calculating every offset from a memory address, whether it is an offset from the beginning of the "global" user memory or an offset from a this or any other pointer. So in terms of performance, the user can fake globals in the narrow cases they are needed using common pointer indirection without losing performance to real global variables. So what else? Are global variables really needed?
Global variables aren't generally bad because of their performance, they're bad because in significantly sized programs, they make it hard to encapsulate everything - there's information "leakage" which can often make it very difficult to figure out what's going on.
Basically the scope of your variables should be only what's required for your code to both work and be relatively easy to understand, and no more. Having global variables in a program which prints out the twelve-times tables is manageable, having them in a multi-million line accounting program is not so good.
I think this is another subject similar to goto - it's a "religious thing".
There is a lot of ways to "work around" globals, but if you are still accessing the same bit of memory in various places in the code you may have a problem.
Global variables are useful for some things, but should definitely be used "with care" (more so than goto, because the scope of misuse is greater).
There are two things that make global variables a problem:
1. It's hard to understand what is being done to the variable.
2. In a multithreaded environment, if a global is written from one thread and read by any other thread, you need synchronisation of some sort.
But there are times when globals are very useful. Having a config variable that holds all your configuration values that came from the config file of the application, for example. The alternative is to store it in some object that gets passed from one function to another, and it's just extra work that doesn't give any benefit. In particular if the config variables are read-only.
As a whole, however, I would suggest avoiding globals.
Global variables imply global state. This makes it impossible to store overlapping state that is local to a given part or function in your program.
For example, let stay we store the credentials of a given user in global variables which are used throughout our program. It will now be a lot more difficult to upgrade our program to allow multiple users at the same time. Had we just passed a user's state as a parameter, to our functions, we would have had a lot less problems upgrading to multiple users.
my question is what is the reason global variables are still needed,
Sometimes you need to access the same data from a lot of different functions. This is when you need globals.
For instance, I am working on a piece of code right now, that looks like this:
static runtime_thread *t0;
void
queue_thread (runtime_thread *newt)
{
t0 = newt;
do_something_else ();
}
void
kill_and_replace_thread (runtime_thread *newt)
{
t0->status = dead;
t0 = newt;
t0->status = runnable;
do_something_else ();
}
Note: Take the above as some sort of mixed C and pseudocode, to give you an idea of where a global is actually useful.
Static Global is almost mandatory when writing any cross platform library. These Global Variables are static so that they stay within the translation unit. There are few if any cross platform libraries that does not use static global variables because they have to hide their platform specific implementation to the user. These platform specific implementations are held in static global variables. Of course, if they use an opaque pointer and require the platform specific implementation to be held in such a structure, they could make a cross platform library without any static global. However, such an object needs to be passed to all functions within such a library. Therefore, you have a pass this opaque pointer everywhere, or make static global variables.
There's also the identifier limit issue. Compilers (especially older ones) have a limit to the number of identifiers they could handle within a scope. Many operating systems still use tons of #define instead of enumerations because their old compilers cannot handle the enumeration constants that bloat their identifiers. A proper rewrite of the header files could solve some of these.
Global variables are considered when you want to use them in every function including main. Also remember that if you initialize a variable globally, its initial value will be same in every function, however you can reinitialize it inside a function to use a different value for that variable in that function. In this way you don't have to declare the same variable again and again in each function. But yes they can cause trouble at times.
List item
Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local
And if you make a mistake while declaring a global variable, then you'll have to apply the changes to the whole program like if you accidentally declared it to be int instead of float

RNGs and global variable avoidance

I'm wondering about this. I've heard that global variables are bad, that they hurt the maintainability, usability, reusability, etc. of the code. But in this case, what can I do otherwise? Namely, I have a "pseudo-random number generator" (PRNG) and as one may know, they involve an internal state that changes every time new random numbers are generated. But this seems like the kind of thing that needs to be a global! Or a "static" member of an RNG class, but that's essentially a global! And globals are bad!
So, what can I do? The obvious thing is to have something like this (really stripped down):
class RNG {
private:
StateType state; // this is the thing one may be tempted
// to make "static", which ruins the
// whole idea
public:
RNG(); // constructor seeds the RNG
~RNG();
int generateRandomInt();
};
But we need to seed that good, if we're going to create an instance of this every time we need a random number in some function or class. Using the clock may not work, since what if two instances of type "RNG" are created too close together? Then they get the same seed and produce the same random sequence. Bad.
We could also create one master RNG object and pass it around with pointers (instead of making it global, which would put us back on square 1), so that classes that need random numbers get a pointer to the RNG object in them. But then I run into a problem involving save/load of these objects to/from disk -- we can't just "save the RNG" for each instance, since we have only one RNG object. We'd have to instead pass an RNG into the load routines, which might give those routines different argument lists than for other objects that don't use the RNG. This would be a problem if, e.g. we wanted to use a common "Saveable" base class for everything that we can load/save. So, what to do? Eliminate the common "Saveable" base and just adopt a convention for how the load/save routines are to be made (but isn't that bad in and of itself? Oy!)?
What is the best solution to this that avoids the hostile-to-maintainability problems of globals yet also does not run into these new problems?
Or is it in fact okay to use a global here, as after all, that's how the "rand()" builtin works anyway? But then I hear that little thing in the back of my mind saying "but... but but but, globals are bad! Bad!" And from what I've read, there seem to be fairly good reasons to think them bad. But it seems like avoiding them creates new kinds of difficulties, like this one. It certainly seems harder to avoid globals than avoid "goto"s, for example.
There's some merit to your reluctance. You may want to substitute another generator for testing for example, that spits out a deterministic sequence that contains some edge cases.
Dependency Injection is one popular method for avoiding globals.
A random number generator is one of those things that is more OK to be global. You can think of it as:
-A RandomNumberFactory, a design pattern that uses a global factory, and it builds random numbers for you. The factory is of course constant semantically (in C++ you might use the keyword "mutable" internally, if that means anything to you.)
-A global constant (global constants are ok, right?) that gives you read-only access to the global constant randomNumber. randomNumber just happens to be non-deterministic, but it's constant in that of course no application is going to write to it.
-And besides, what's the worst that could happen? In a multithreaded application your RNG will yield non-deterministic behavior? Gasp. As #Mark Ransom pointed out above, yes that is actually a drawback as it makes testing harder. If this is a concern to you, you might consider a design pattern that writes this out.
It sometimes makes sense to use globals. No one can categorically say your code should not have any global variables, period.
What you do need is to be aware of the issues that can arise from global variables. If your application's logic needs global variables and it is possible for it to be called from a multi-threaded environment, then there is nothing inherently wrong with that, but you must take care to use locking, mutexes, and/or atomic reads/writes to ensure correct behavior.

external side effect in constructor

Look at this code:
#include <framework_i_hate.h>
int main() {
XFile file("./my_file.xxxx", "create");
XObject object("my_object");
// modify the object
object.Write();
}
Try to guess where object will be saved... yes, you guessed it. I think this is too magic, I'd like to write something like object.Save(file), but it's not necessary. Obviously there is global variable inside framework_i_hate.h that it is modified during the file constructor. What do you think about this side effect inside constructor?
How can this behavior be hidden?
A bonus to who guess the framework.
Very muddled hard to understand post and the question in the end is very rhetorical.
Global variables are evil, what else to add?
What can be said about this that isn't already obvious enough: It's a fairly nasty side effect, because:
the resulting behaviour is unexpected and not predictable at all, unless you know that framework well.
global program state usually isn't a good idea in object-oriented programming. (In fact, global state is probably never a good idea, so best avoid it if you can.)
it's fairly likely that this framework isn't thread-safe, either. (Think about what happens when two concurrent threads both create an XFile object each, and one of these threads then writes an XObject... where will it end up being saved?)
While this thread is tagged C++ and not about .NET, I have seen this "anti-pattern" before in a less severe and much more sane form, namely with DB transaction scopes.
I'd prefer to see the relationship between XFile and XObject be explicit, I agree that this "magic" is too well hidden. I also question why the object is given a name, unless there are other parts of the API where the name is significant.
Global variables are despised for many reasons, this is just one example.