- Home /
Are C# Global Variables Safe In Unity?
Hello all,
Coming from a C++ background, I have always stayed away from creating global variables, even though in C++, they are not created inside a class, and are a bad practice. I was wondering how safe or problematic it is in Unity to have global variables hanging around at the top of your class, inside a script. Is the scripting environment of Unity (for C#) suppose to allow for a ton of global variables, or should we as developers declare all our variables in methods?
I have seen Unity tutorials (both form the official site and on YouTube) where the developer/tutor creates global variables for working in a class. Is this the correct way of doing this in C#?
Cheers all
What do you mean by a "global variable"? The fact that everything has to be in a class means that there is nothing in C# that corresponds to a C++ global. It would help if you provided a link to one of those tutorials you mention, along with an indication (if not already there) of what it is that you're calling a "global variable".
If you are referring to singleton pattern which relays on static vars, then, even though it is used by pretty much all official tutorials, it is considered a bad practice in general which begs the question what strategy is better.
Unfortunately there is not one pattern to rule them all thus it is more of which one will be best for each occasion. For small projects singeton is quite good as it allows fast progression on large ones can end up being a nightmare.
Apart from that, static vars can cause issues with memory management.
Won't go deep on any of this, google can direct you on several articles on the subject.
Cheers!
Oh forgot to mention that static vars are not serialized by Unity's serializer.
Answer by Bunny83 · Jan 12, 2018 at 02:53 PM
Well there are several things we have to differentiate.
First of all what is considered a global variable
Second most people just repeat the phrase "globals are evil" without understanding why. If you understand the reason why you wouldn't have to ask the question ever again as it doesn't matter which language, which environment or which application type we talk about.
Generally a global variable is a variable (data / state) that exist once globally and is accessible globally. Now we hit the next definition issue. What is "globally" ? It can mean different things depending on your viewing scope. In programming globally usually refers to the scope of a single program / application. However it could also mean something global in the system which is provided by the OS. System wide global information are things like the current date / time, the file system and more abstractly even socket connections. In the program / appication context global variables are generally static variables.
The main problem with global state is that any system which has access to it could alter the state at any time. In a small controlled environment it's relatively easy to keep track of who is changing and who is reading the global state. However in more complex systems, especially when multiple programmers work on different modules independently nobody knows who might change a global variable.
In short: global state introduces "uncertainty" in an otherwise full deterministic program. Apart from the uncertainty global state also causes many problems when you create unit tests. A unit test is meant to test the functionality of a single class / component / module. For this purpose you want to create a controlled environment so you can test the different features in a deterministic way. If a module works with references to other instances, those instances can be replaced with mock objects to simulate a certain situation in order to test a specific feature. Global state however introduces external dependencies which could be changed by an unrelated system.
Of course there is a lot global state in Unity which can't be controlled directly. However those are usually environmental properties. Like Time.time, AudioListener.volume but also the whole scene management and gameobject system.
So in general using global state is never "safe" (whatever that means). We can't really live without some global state, but you should try to minimize it.
ps: I often read things like: "don't use global / static variable, use singletons instead". Singletons are also global state. Some people think global state are just static variables, but that includes what those static variables contains. A singleton is just an instance stored in a static variable. It introduces the same issues as seperate static variables. Singletons just have the advantage that they are serializable since they are instances, you can use inheritance and have the proper version being instantiated at runtime, a lazy loaded / created singleton doesn't require memory if it's not used and if due to refactoring you actually need several instances the change is easier compared to having tons of static variables. A common scenario is converting a singleplayer game into a multiplayer game. In the single player game you might create your Player class as singleton. However in a multiplayer environment you would have several players. Here you only need to change / update the way you access the correct Player instance. If you would have used static variables for everything you would have to rewrite your whole Player class and every bit that uses those variables.
Keep in mind that instance variables are not "global" variables. Yes if you make a variable public it's globally accessible but it's not a global variable or global state as an instance variable is bound to a specific instance of the class. If you should make your variables private or public is a completely different story and is about encapsulation. In strict OOP you would never use public variables. A class represents a certain amount of state and functionality. In strict OOP the state of a class can only be changed from within the class or through methods that the class provides. Though as i said this has nothing to do with global state / global variables
Answer by DaDonik · Jan 12, 2018 at 01:58 PM
In general there is nothing wrong with having global variables. It's not neccessarily the pinnacle of good design, but sometimes they are just too convenient.
Most tutorials i have seen are not really what i would call 'good code'. They are often just a vehicle to get you acustomed to the API.
An example where i do use global variables would be the following:
public static class Const
{
public static int InvalidId = -1;
}
Which will allow you to refer to that by Const.InvalidId anywhere in your codebase. Apart from such basic values that will be used throughout my code, i try to avoid global variables.
Apart from that, i also use static classes for game wide manager classes, which would probably also fall into the category of 'global variables'.
Note that your example is not really a good one. You seem to want to use a constant here. So it would be better to do
public const int InvalidId = -1;
or
public static readonly int InvalidId = -1;
The first example creates a compile time constant. This constant doesn't require any memory as it's simply replaced by the number "-1" at compile time. So in the compiled assembly the constant doesn't exist anymore.
The second example creates an actual static field which holds the number "-1" but is readonly. Note that even this is a global variable, it's an immutable global variable. The only problem with global state is if it's mutable. In your case it is mutable / changable because everyone could do
Const.InvalidId = 5;
Oh thanks, i missed that. Looked up my actual code an i have it as const in there...
Answer by Harinezumi · Jan 12, 2018 at 02:57 PM
Based on your statement
even though in C++, [global variables] are not created inside a class
I think you are confusing global variables with member variables.
Example:
public class ExampleClass {
private int privateMemberVariable;
public int publicMemberVariable;
[SerializeField] private int privateMemberVariableExposedToUnity;
public static int public classLevelPublicVariable;
}
The first one privateMemberVariable
, is a completely normal member variable, a separate one existing for each instance of the class ExampleClass
. In C++ this would be in the private section of the class declaration.
The next one, publicMemberVariable
is the same as the private one (one separate variable per instance), except you can access it from other classes (and their functions). Not a good practice, try to avoid it, even though you see Unity examples use public all the time. That is because declaring a member variable public exposes it to the Inspector in the Unity Editor, but the better way is...
privateMemberVariableExposedToUnity
which is only accessible from ExampleClass
, but is still exposed due to the annotation [SerializeField]
.
Finally, there is classLevelPublicVariable
, which is a static variable, meaning that only one exists of it per class, accessible from all instances from this class (and from outside as well, because it is public). Unless you know what you are doing, don't use static variables.
None of these variables are global, all of them are related to the class ExampleClass
, because C# is (mostly) object oriented language. Using these types of variables is not just good practice, it is the "only" way to store data between functions (let's not get into weird ways).
Answer by $$anonymous$$ · Jan 12, 2018 at 06:34 PM
Thank you all for your replies. They are truly welcomed and informative.
Thank you.
You can upvote answers or comments, or even accept an answer if you think it resolved your question ;)
Answer by KonfuPanda · Jan 12, 2018 at 01:58 PM
You will not get a definitive answer even because you basically ask two questions:
Is it safe/good practice to use global variables in C#?
Is it safe/good practive to use global variables in C# in Unity?
As I am not experienced in C# development outside of Unity but I am in the latter one, so I will try to answer the 2nd question. In the context of Unity it is in my opinion often useful to define global variables because or various reasons. Possible usecases are:
Editor variables
You want to define a variable which should be filled from the editor. Therefore you need to expose it via making it public or adding a [SerializeField] attribute.
Cached variables
Because your game should run efficient and smooth it is oftentimes better to cache stuff than calling a search function every time you use it. Again, for this you need a global variable, e.g. a list.
Library class
Imagine you have a class which has a texture library which you fill in the editor. In another class you use this library to assign a specific texture to a gameobject. This library will also be global.
There are many more examples where it does make sense to a variable global. A good guide is, if you use a variable multiple times, especially if it is in an Update function, make it global, if you use it only once, you can make it local. On the other hand, global variables need RAM, so if you have a lot of processing power but only limited RAM, which may be the case on mobile platforms, and you use it the global variable only on rare occasions, make it local.