So, in summary, Singletons are bad, and the alternative is to use a Dependency Injection framework. I happen to use Castle Windsor, but you are spoilt for choice. See this page from back in for a list of available frameworks. First of all for dependency injection to be "stateful", you would need to use singletons, so people saying this is somehow an alternative are mistaken. People use global context objects all the time Even session state for example is in essence a global variable. Passing everything around whether by dependency injection or not isn't always the best solution.
I work on a very large application currently that uses a lot of global context objects singletons injected via an IoC container and it has never been a problem to debug. Especially with an event driven architecture it can be preferred to use global context objects vs. Depends who you ask. Anything can be abused and it also depends on the type of application. Using static variables for instance in a web app is completely different than a desktop app. If you can avoid global variables, then do so, but sometimes they have their uses.
At the very least make sure your global data is in a clear contextual object. As far as debugging, nothing a call stack and some breakpoints can't solve. I want to emphasize that blindly using global variables is a bad idea.
Functions should be reusable and shouldn't care where the data comes from -- referring to global variables couples the function with a specific data input.
This is why it should be passed in and why dependency injection can be helpful, although you are still dealing with a centralized context store via singletons. Some people think dependency injection is bad, including the creator of Linq, but that isn't going to stop people from using it, including myself.
Ultimately experience will be your best teacher. There are times to follow rules and times to break them. If all configuration data is passed explicitly, the components become much easier to test and you never need to worry how to bootstrap a global configuration value for multiple tests, maybe even in parallel.
Well, for one, you can run in to exactly the same issue that you can with singletons. What today looks like a "global thing I only need one of" will suddenly turn in to something you need more of down the road. For instance, today you create this global config system because you want one global configuration for the entire system.
A few years down the road, you port to another system and someone says "hey, you know, this might work better if there were one general global configuration and one platform specific configuration. This isn't some random example Considering that the cost of making something non-global is usually trivial, it's silly to do so. You're just creating future problems. The other problem curiously is that they make an application difficult to scale because thay are not "global" enough.
The scope of a global variable is the process. If you want to scale your application up by using multiple processes or by running on multiple servers you cannot. At least not until you factor out all the globals and replace them with some other mechanism. Mutable global state is evil because it's very hard for our brain to take into account more than a few parameters at a time and figure out how they combine both from a timing perspective and a value perspective to affect something.
Therefore, we are very bad at debugging or testing an object whose behavior has more than a few external reasons to be altered during the execution of a program. Let alone when we have to reason about dozens of these objects taken together.
State is unavoidable in any real application. You can wrap it up any way you like, but a spreadsheet must contain data in cells. You can make cell objects with only functions as an interface, but that doesn't restrict how many places can call a method on the cell and change the data. You build whole object hierarchies to try to hide interfaces so other parts of the code can't change the data by default.
That doesn't prevent a reference to the containing object from being passed around arbitrarily. Nor does any of that eliminate concurrency issues by itself. It does make it harder to proliferate access to data, but it doesn't actually eliminate the perceived problems with globals. If someone wants to modify a piece of state, they're going to do it weather it's global or through a complex API the later will only discourage, not prevent.
The true reason not to use global storage is to avoid name collisions. If you load multiple modules which declare the same global name, you either have undefined behavior very hard to debug because unit tests will pass or a linker error I'm thinking C - Does your linker warn or fail on this?
If you want to reuse code, you've got to be able to grab a module from another place and not have it accidentally step on your global because they used one with the same name. Or if you're lucky and get an error, you don't want to have to change all the references in one section of code to prevent the collision. Arguably this means no globals, since immutable objects are in a sense not really stateful since they never have a state transition.
Joe-E is one example, and David Wagner explains the decision thus:. Analysis of who has access to an object and the principle of least privilege are both subverted when capabilities are stored in global variables and thus are potentially readable by any part of the program.
Once an object is globally available, it is no longer possible to limit the scope of analysis: access to the object is a privilege that cannot be withheld from any code in the program. Joe-E avoids these problems by verifying that the global scope contains no capabilities, only immutable data. Global mutable state is similar to DLL hell. Over time, different pieces of a large system will require subtly different behavior from shared pieces of mutable state.
Solving DLL hell and shared mutable state inconsistencies requires large-scale coordination between disparate teams. These problems would not occur had the global state been properly scoped to begin with. When it's easy to see and access all of the global state, programmers invariably end up doing so. What you get is unspoken and difficult to track dependencies int blahblah means that array foo is valid in whatever. Essentially it makes it nearly impossible to maintain program invariants since everything can be twiddled independently.
That said, it can be done way back when it was the only way in some systems , but those skills are lost. They revolve mostly around coding and naming conventions- the field has moved on for good reason. Globals aren't that bad. As stated in several other answers, the real problem with them is that what is, today, your global folder path may, tomorrow, be one of several, or even hundreds.
If you're writing a quick, one-off program, use globals if it's easier. Generally, though, allowing for multiples even when you only think you need one is the way to go. It's not pleasant to have to restructure a large complex program that suddenly needs to talk to two databases. But they do not hurt reliability.
Any data referenced from many places in your program can cause problems if it changes unexpectedly. Enumerators choke when the collection they're enumerating is changed in mid-enumeration.
Event queue events can play tricks on each other. Threads can always wreak havok. Anything that is not a local variable or unchangable field is a problem. Globals are this sort of problem, but you're not going to fix that by making them non-global. If you are about to write to a file and the folder path changes, the change and the write need to be synchronized.
As one of a thousand things that could go wrong, say you grab the path, then that directory gets deleted, then the folder path is changed to a good directory, then you try and write to the deleted directory.
The problem exists whether the folder path is global or is one of a thousand the program is currently using. There is a real problem with fields that can be accessed by different events on a queue, different levels of recursion, or different threads. To make it simple and simplistic : local variables are good and fields are bad. But former globals are still going to be fields, so this however critically important issue does not apply to the Good or Evil status of Global fields.
Note that you can have similar problems with an event queue or recursive calls, but multithreading is by far the worst. Consider the following code:. If filePath is a local variable or some kind of constant, your program is not going to fail when running because filePath is null.
The check always works. No other thread can change its value. Otherwise , there are no guarantees. Any other thread can change the value at any time, and they often do. As several other answers point out, this creates serious problems for testing. The above statement can work a billion times, getting it through extensive and comprehensive testing, then blow up once in production. The users won't be able to reproduce the problem, and it won't happen again until they've convinced themselves they were seeing things and forgotten it.
Globals definitely have this problem, and if you can eliminate them completely or replace them with constants or local variables, that's a very good thing. If you have stateless code running on a web server, you probably can. Typically, all your multithreading problems can be taken on by the database. But if your program has to remember things from one user action to the next, you will have fields accessable by any running threads.
Switching a global to such a non-global field will not help reliability. I'm not gonna tell if global variables are either good or bad, but what I'm going to add to the discussion is to tell the fact that if you are not using global state, then you are probably wasting a lot of memory, especially when you use classess to store their dependencies in fields. For example: imagine a following scenario: You have a 10x10 grid which is made of classess "Board" and "Tile". Let's say now that "Tile" has 2 "byte" type fields storing it's coordinate.
This gives a total of bytes for 10x10 tiles setup. Now for the case where the Board is in global scope, a single object accessible from each tile you only would have to get 2 bytes of memory per each tile, that's the x and y coordinate bytes. This would give only bytes.
The more globals you have, the greater the chance of introducing duplicates, and thus breaking things when duplicates get out of sync. Keeping all of the globals in your falible human memory is becomes both necessary and pain. A function that uses globals effectively has extra "hidden" parameters, making refactoring it harder. Global state isn't evil, but it does come at a definite cost — use it when the benefit outweighs the cost.
Sign up to join this community. Global variables are bad, if they allow you to manipulate aspects of a program that should be only modified locally.
In OOP globals often conflict with the encapsulation-idea. Global variables have their place and like many people said knowing where and when to use them can be complicated. So I think rather than get into the nitty gritty of the why, how, when, and where of global variables your professor decided to just ban. Who knows, he might un-ban them in the future. Mindlessly removing them for the sake of is just that When you understand the pros and cons better make your own decision.
I would like to argue against the point being made throughout this thread that it makes multi-threading harder or impossible per se. Global variables are shared state, but the alternatives to globals e. The problem with multi-threading is how to properly use shared state, not whether that state happens to be shared through a global variable or something else.
Most of the time when you do multi-threading you need to share something. In a producer-consumer pattern for example, you might share some thread-safe queue that contains the work units. And you are allowed to share it because that data structure is thread-safe. Whether that queue is global or not is completely irrelevant when it comes to thread-safety. The implied hope expressed throughout this thread that transforming a program from single-threaded to multi-threaded will be easier when not using globals is naive.
Yes, globals make it easier to shoot yourself in the foot, but there's a lot of ways to shoot yourself. I'm not advocating globals, as the other points still stand, my point is merely that the number of threads in a program has nothing to do with variable scope. No they are not bad at all. You need to look at the machine code produced by the compiler to make this determination, sometimes it is far far worse to use a local than a global.
Also note that putting "static" on a local variable is basically making it a global and creates other ugly problems that a real global would solve. Globals give you clean control over your memory usage as well, something far more difficult to do with locals. These days that only matters in embedded environments where memory is quite limited. Something to know before you assume that embedded is the same as other environments and assume the programming rules are the same across the board.
It is good that you question the rules being taught, most of them are not for the reasons you are being told. The most important lesson though is not that this is a rule to carry with you forever, but this is a rule required to honor in order to pass this class and move forward. In life you will find that for company XYZ you will have other programming rules that you in the end will have to honor in order to keep getting a paycheck.
In both situations you can argue the rule, but I think you will have far better luck at a job than at school. You are just another of many students, your seat will be replaced soon, the professors wont, at a job you are one of a small team of players that have to see this product to the end and in that environment the rules developed are for the benefit of the team members as well as the product and the company, so if everyone is like minded or if for the particular product there is good engineering reason to violate something you learned in college or some book on generic programming, then sell your idea to the team and write it down as a valid if not the preferred method.
Everything is fair game in the real world. If you follow all of the programming rules taught to you in school or books your programming career will be extremely limited. You can likely survive and have a fruitful career, but the breadth and width of the environments available to you will be extremely limited.
If you know how and why the rule is there and can defend it, thats good, if you only reason is "because my teacher said so", well thats not so good. Note that topics like this are often argued in the workplace and will continue to be, as compilers and processors and languages evolve so do these kinds of rules and without defending your position and possibly being taught a lesson by someone with another opinion you wont move forward.
In the mean time, then just do whatever the one that speaks the loudest or carries the biggest stick says until such a time as you are the one that yells the loudest and carries the biggest stick. It quickly becomes impossible to understand what is going on at any one point unless you know the entire project. This means that you can easily get in the habit of using them while learning. This is what your professor is trying to protect you from.
Global are good when it comes to configuration. So we can change one configuration and the changes are directed to entire project. But I must warn you would have to be very smart to use globals. Use of Global variables actually depends on the requirements. Its advantage is that,it reduces the overhead of passing the values repeatedly. But your professor is right because it raises security issues so use of global variables should be avoided as much as possible. Global variables also create problems which are sometimes difficult to debug.
Situations when the variables values is getting modified on runtime. At that moment its difficult to identify which part of code is modifying it and on what conditions.
In the end of the day, your program or app can still work but its a matter of being tidy and having a complete understanding of whats going on. If you share a variable value among all functions, it may become difficult to trace what function is changing the value if the function does so and makes debugging a million times harder. Sooner or later you will need to change how that variable is set or what happens when it is accessed, or you just need to hunt down where it is changed.
It is practically always better to not have global variables. Just write the dam get and set methods, and be gland you when you need them a day, week or month later. I usually use globals for values that are rarely changed like singletons or function pointers to functions in dynamically loaded library. Using mutable globals in multithreaded applications tends to lead to hard to track bug so I try to avoid this as a general rule. Using a global instead of passing an argument is often faster but if you're writing a multithreaded application, which you often do nowadays, it generally doesn't work very well you can use thread-statics but then the performance gain is questionable.
As mentioned, race conditions need to be handled. We use a single instance of a class for this information and it is carefully managed.
In a multi-threaded application, use local variables in place of global variables to avoid a race condition. A race condition occurs when multiple thread access a shared resource, with at least one thread having a write access to the data.
Then, the result of the program is not predictable, and depends on the order of accesses to the data by different threads. Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams? Collectives on Stack Overflow.
Learn more. Are global variables bad? Asked 12 years, 9 months ago. Active 2 years, 9 months ago. Viewed k times. Improve this question. I'll bite in case he's trying to tell a joke I think that this question was pretty interesting! Software development is still facing the same old pitfalls since the beginning and programmers often still don't know that using global variables, gotos, short named variable IS NOT the problem.
Bad code is written every day without using them. How can we possibly answer? He hasn't told us how bad his professor thinks they are. The problem I was talking about is that many developers know that they should not use global variables but they just DON'T know why!
Same problem as so called "good practices": they are good practices in SOME contexts, not in all context. Using them MAY create unmaintenable code. There are very few good uses for global variables. One possible, but debatable use, would be a global "configuration" object, that reads in a config file once at startup. Show 6 more comments. Active Oldest Votes.
Improve this answer. Brian Rasmussen Brian Rasmussen k 34 34 gold badges silver badges bronze badges. This answer is really good. Combine this with the 'minimize variable scope' answer stackoverflow. Substitute 'class' for 'application' and 'object state' for 'global state' and you make exactly the same argument for not using member variables aka fields in classes. The real answer is use them when appropriate.
Few perhaps silly questions: 1 If you want to know which functions read and write these variables, couldn't you just use the "find" function in an editor to spot the cases where the values in these variables are modified? Perhaps an example of that would work for me. Show 5 more comments. The important thing is to remember the overall goal: clarity The "no global variables" rule is there because most of the time, global variables make the meaning of code less clear.
However, like many rules, people remember the rule, and not what the rule was intended to do. Tom West Tom West 1, 1 1 gold badge 11 11 silver badges 17 17 bronze badges. Suggesting using a global instead of passing variables is a recipe for making your code not reusable, and unsafe for multi-threading — Juan Mendes. Suggesting globals in the right circumstances is a recipe for clearer and higher performing code. For example, if you have a function that reads Winsock recv , why constantly create and deallocate this buffer within every call?
Make the buffer a global. Multiple threads won't be reading it anyway. Just curious, what program double the size of the code by passing parameters around to avoid global variables?
In my experience, using global variables may solve data exposure problems, but there are usually additional complex logic that you need to add in order to make sure these magical variables behave properly. If someone's passing around variables, then they've not learnt what an object is. Using the reference to this object is then at worst passing around a pointer. I'd say that the rule isn't just clarity, but testability too - and using a non-global tends to make things much easier to test.
My personal example of doubling code size was a large Fortran program, circa Local variables are much safer because other functions can not affect them directly. How do you fix it? One of the key reasons to declare local variables as close to where they are used as possible is because doing so minimizes the amount of code you need to look through to understand what the variable does. Global variables are at the opposite end of the spectrum -- because they can be accessed anywhere, you might have to look through the entire program to understand their usage.
In small programs, this might not be an issue. In large ones, it will be. Global variables also make your program less modular and less flexible. A function that utilizes nothing but its parameters and has no side effects is perfectly modular.
Modularity helps both in understanding what a program does, as well as with reusability. Global variables reduce modularity significantly.
It is much more likely to break if you change a global variable that impacts how your program actually functions. The initialization order problem of global variables.
Initialization of static variables which includes global variables happens as part of program startup, before execution of the main function. This proceeds in two phases. The first phase is called static initialization. In the static initialization phase, global variables with constexpr initializers including literals are initialized to those values.
Also, global variables without initializers are zero-initialized. The second phase is called dynamic initialization.
0コメント