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

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

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’.

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).

Thank you all for your replies. They are truly welcomed and informative.

Thank you.

You will not get a definitive answer even because you basically ask two questions:

  1. Is it safe/good practice to use
    global variables in C#?
  2. 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.