- Home /
Csharp has no true global variable?
Global variables are bad. No argument there.
And I know there are many, many, many and then even more questions on this subject, but I'm not happy with the answers there. None really address the global var issue, they just give either `static` as a solution (not valid) or some good coding practices on how we should not use globals (quite valid).
Well, thing is, global variables are needed.
Specially if you want to create bad design and have headaches on a growing application. And, eventually, to keep serious stuff like logs or caches.
If we really have no native global var in csharp, what can we do to keep data among whole scene changes, with all objects being naturally destructed, other than manually using DontDestroyOnLoad and/or LoadLevelAdditive?
edit / disclaimer
If you want more history on what happened here, go ahead and check the edit revisions. I've decided it's better to remove the clutter (and the shame).
I should have mentioned I'm also aware of Singletons and their issues. I thought it would be evident from my immediate answer with the singleton Toolbox, but I was wrong.
I should also have explained what I mean by true global var. I actually expected some people would not get it. Heck, I still don't quite get it. What I mean is there is no global scope (other than classes). Thus, no global members. And static members would not be the same thing because they are in fact in side of a class. But, in practice, what all that means? Well...
Turns out it means basically nothing. For many circumstances I believed static wasn't a global var. But it is. There are some few differences with that "true global var concept" on the way it's allocated in memory, so there are cautions to take but that's just if *you are writing unsafe code or doing some sort of heavy interoperating with unmanaged code*.
So this whole question is mostly dull (or even d'oh). Sorry.
So, you are aware that not every object you create has to be attached to a GameObject (ie. inherit from $$anonymous$$onobehavior)? You still have the option to make singletons.
Can you elaborate on how anything but a monobehavior is a waste?
I'm totally not understanding the problem here. What kind of global variable do you want that is different from a public static?
A static variable will keep its data through scene changes.
I'm also curious as to why you think non-monobehaviour classes are a waste.
What do you mean by no 'true' global variable?
If i do, public class A { public static int Value; }
then A.Value is accessible globaly, i.e. a true global variable.
Ok, i give you an upvote since you got two downvotes without a proper reason ;)
Answer by SilentSin · Nov 16, 2013 at 12:33 AM
"The problem with A.Value if nothing else, is conceptual. It only exists while A exists. Guess what? If A inherits from MonoBehavior it can be destroyed and A.Value becomes null. And this can easily happen by accident. If you write code thinking "There, I just created the static as global and as such it's all fine, it won't lose its value unless I explicitly say so". Not that simple. Not a true global var."
Your assumption is misguided.
Instances of a class have nothing to do with that class's statics. Destroying an instance will not null any static variables unless you have code that explicitly does so in OnDestroy().
If this isn't an answer, then I'm still not understanding the problem. I mean, you said "The problem with A.Value if nothing else, is conceptual. It only exists while A exists." And since we now know that the second sentence of that is untrue, then there doesn't seem to be a problem anymore. I thought that was what answers were supposed to do.
A.Value is a value that can be accessed from anywhere and will never be destroyed unless you set it to null. The only difference I can see between it and what you seem to be describing as a global is that it needs to be accessed through "A." rather than just referring to "Value". If that's the problem, then c# simply doesn't have a solution for it.
You're right, just tested it. Thanks! I will fix it. But this is far from an answer.
Because I got a bad example, and now I'm really not sure exactly where static's problem is... But I'm pretty sure there is a problem with static and that csharp has no global var. If you're telling me csharp does have global var I'm gonna need much more evidence.
No, I'm telling you that c# doesn't have global variables. http://social.msdn.microsoft.com/Forums/en-US/3ea35ea5-6912-44f0-828a-666cb12c6e0c/c-global-variables?forum=vssmartdevicesnative
If you're not sure what the problem is, then doesn't that mean that using a static will work perfectly fine for the situation you want to use it for?
@SilentSin nope, I've used static, and it broke everything. I didn't know it was static issue. Eventually I replaced it with singleton and it was fine. But that's at work, I'm home now and have limited access to what's done there until monday. Even when I can take a closer look, the project is quite a mess and quite big. It wouldn't be easy to diagnose and wouldn't be doable to replace all back to static just to find the problem.
But I think all that's a little beyond the point of the question. That msdn link looks quite authoritative, that's good. Looks like we are only disagreeing on how bad the static is to work as global var... I'll find the issue or give up in 7 days or so. Gotta go for now, sorry. And thanks for sticking around!
The problems seems to arise from the fact that "global" is used in different contexts. First there is the global namespace. In C# namespaces can never contain any data / variables / methods. Namespaces contains only type definitions. C# enforces OOP that way. Everything has to belong to a class.
Second there's the scope. Basically there are two different scopes: The class scope and the instance scope. The scope forms a hierarchy just like the namespaces do. Inside a class the class scope is part of the instance scope. So you can call a static method(class scope) from an instance method(instance scope).
Finally there's an objects extent. The extent defines the lifetime of a variable.
Variables in the class scope have an extent over the lifetime of the class itself which usually until the application quits.
The term "global variable" usually could mean either of those topics, most the time a combination of those.
You ask for a "true" global variable, now it's up to you how you define it. You can't ask for something when you don't know what you mean.
ps: Strictly you have to divide the scope further down since there are multiple "versions" of the sea$$anonymous$$gly same scope. The difference here is public / private / protected / internal which differentiate depending on from where you access the scope.
Answer by sotirosn · Nov 15, 2013 at 11:28 AM
I have almost 15 years of programming experience and it is very useful indeed to have global singletons. It is commonly taught in schools that global variables are 'bad' because the novice programmer may try something as such.
public static int a;
public static int b;
public static int c;
void AddNumbers() { c = a + b; }
void Main() {
a = 5; b = 3;
AddNumbers();
Debug.Log(c); // should output 8
}
As you can see there are issues here. For example another thread may change a and b before the AddNumbers() function is called, not to mention it is confusing to read.
However global singletons are great.
public class HUD {
public static HUD instance;
public void Awake() {
if(instance) {
Debug.LogError("HUD already instantiated!");
return;
}
instance = this;
}
public static void Add(HUDElement element) {
....
}
....
}
public HUDElement {
public void Awake() {
HUD.Add(this);
}
}
Singletons are good if the application needs exactly one of them. Some built in unity globals are Time.deltaTime, and Input.mousePosition. How are these bad?
As for using my own global variables(which change) and not just singletons(which are set once), I have used a mouse picker to let the user select an object. I set a global variable called 'selected'. All the rest of my code can access the variable as UserInterface.selected. I think this coding practice is fine and has served me well. Believing that globals are bad is a common misconception.
EDIT >>
Looking at your question again SilentSin are you more asking about persistency in Unity rather than globals in c#? Unity destroys gameobjects when you load another level. So if you do have a singleton with a public static gameobject or component then it will be nulled when the level changes. You could put all your info into a static non-unity class.
public class PersistantInfo { public static PersistantInfo instance; members.. }
All the members will keep their data unless they are monobehaviours attached to gameobjects in the scene. To save these you need DontDestroyOnLoad();
You can also use OnLevelWasLoaded(int level) and Awake() { Application.levelLoaded } to better manage who to destroy and who to let live.
So maybe
class Player : MonoBehaviour {
void Awake() {
DontDestroyOnLoad(gameObject);
}
void OnLevelWasLoaded(int level) {
switch(level) {
case startMenu: Destroy(gameObject); return;
case level1: MoveToLevelStart(); return;
case level2: MoveToLevelStart(); return;
case gameOver: Destroy(gameObject); return;
}
}
Make sure Player is attached to a top level scene object. DontDestroyOnLoad does not work if the parent object is destroyed.
Well, in some situations global state is unavoidable, but if possible it should be avoided by any means.
See this great talk about singletons and global state
Sure singletons might work well in a small application, but they make code:
hard to debug
hard to test
almost non reusable
strongly bound to other classes.
As said there are some global states which can't entirely avoided. Like system time for example. But it can be isolated by wrapping a global state into a provider class instance. That way you can test the whole thing without being bould to the real time since you can replace the provider by a mock. This even allows testing at fake framerates.
sotirosn, sorry I didn't talk explicitly about singletons. They are indeed a great solution. But I had already gone one step further and suggested the Toolbox, which is a singleton. I'm just sad nobody realized that. I mean, your answer still sounds one step behind from $$anonymous$$e. In any case, here are some good thread safe singleton implementations: http://csharpindepth.com/Articles/General/Singleton.aspx
@Bunny83 It's only true singletons may and usually do make code hard to debug, etc. But none of the items you pointed is singleton's fault any more than global vars and their abuse. I completely agree with everything else you said.
@Cawas: No, it seems you don't get the point. The problem is the global state and the singleton design pattern is nothing but a global state. It makes absolutely no difference for the points i've mentioned above if you use a singleton or just a static class with bunch of static variables. The result is 100% the same.
Everything a singleton references becomes part of the global state the singleton represents. Actually it's just more complicated to access your stuff. The problems static data causes are still there.
Watch the video i've linked above.
He makes a difference between the concept of a singleton and the singleton design pattern. The concept doesn't need a static variable at all.
@Bunny83 to me you just repeated what I said now, except when you talk about the video. :P
Sorry again for all the confusion my question brough, @sotirosn. I just edited it again, hopefully for a last time.
Answer by RyanZimmerman87 · Nov 16, 2013 at 10:51 PM
"And there will be rare but useful cases where they can be properly applied. Just not if you want global vars."
Maybe it just depends on what kind of project you're working on, but for an action RPG it seems that it's not really a rare case that they are useful.
Many of my scripts variables like all the player information for the custom stats based on your armor, your skill tree, where you spend your stat points, etc. they all need to be accessed by multiple scripts and in multiple scenes. There is just one instance of these variables in the entire project and there are many of these variables. There would be no reason not to use public static variables in a case like this, hardly a rare case.
I also have all kinds of other variables that must be easily accessed from any script and that will only ever have 1 value at any time during game play. Things like option menu logic to make sure that the multiple menus and panels never cause any conflicts or interference with each other.
For example:
public static bool gamePausedBool = false;
public static bool mainPauseMenuBool = false;
public static bool optionsMenuBool;
public static bool inventoryBool;
public static bool playerStatsBool;
public static bool skillTreeBool;
public static bool glovesEquippedBool = false;
public static bool bootsEquippedBool = false;
public static bool helmEquippedBool = false;
public static bool chestEquippedBool = false;
public static bool beltEquippedBool = false;
public static bool storeBool = false;
public static bool dropItemSelectedBool;
public static bool itemSlot1AvailableBool;
public static bool itemSlot2AvailableBool;
//etc
All of those are just for my GUIButtonsScript
I agree with Hoeloe that it is very useful to just set up a GlobalDataScript where you keep the majority of your global public static variables organized. You can load up all these variables locally from the PlayerPrefs on Awake() and then set new local private variables for all the other scripts that regularly use them in the other scripts Start() functions.
Here's an example of some of my GlobalDataScript stuff, just trying to give a good example of how they are useful to me. I heavily rely on them and they work perfectly, so I don't quite understand what's the problem with them.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class GlobalDataScript : MonoBehaviour
{
public static bool videoPlayingBool = false;
public static int globalTotalHealthPotions;
public static int globalTotalManaPotions;
public static int globalTotalCrystals;
public static int globalLevelsUnlocked;
public static int currentLevelInt;
public static int inventoryItemSlotsUsed;
public static int inventoryFirstItemSlot;
public static int inventorySecondItemSlot;
//etc
public static int inventoryFirstItemType;
public static int inventorySecondItemType;
//etc
public static int inventoryFirstItemID;
public static int inventorySecondItemID;
//etc
public static int globalPlayerStrength;
public static int globalPlayerDexterity;
public static int globalPlayerIntelligence;
public static int globalPlayerVitality;
public static int globalPlayerArmor;
public static float playerXPTotal;
public static int playerStatPointsAvailable;
public static int playerSkillPointsAvailable;
public static int playerLevel;
public static int playerAtStoreInt;
public static int tierOneArmorPiecesFound;
public static int tierTwoArmorPiecesFound;
public static int tierThreeArmorPiecesFound;
public static int monsterKillCount = 0;
public static bool loadingScreenImageBool;
public static int arenaLevelsUnlocked;
public static bool globalStoryActiveBool;
public static float playerHealthBeforeArmorChange;
public static float playerEnergyBeforeArmorChange;
public static float globalDebugCounter;
public static int globalBloodSettings;
public static int globalMusicSettings;
public static int playerHasPetInt;
public static int playerPetTypeInt;
//set all variables on Awake()
//allows easy access and storage of large amounts of global variables
//can all be used locally with new private variables on any other scripts via Start()
void Awake()
{
globalTotalHealthPotions = PlayerPrefs.GetInt ("Total Health Potions");
globalTotalManaPotions = PlayerPrefs.GetInt ("Total Mana Potions");
globalTotalCrystals = PlayerPrefs.GetInt ("Total Crystals");
globalLevelsUnlocked = PlayerPrefs.GetInt ("Levels Unlocked");
arenaLevelsUnlocked = PlayerPrefs.GetInt ("Arena Levels Unlocked", 0);
//etc
}
Had to make this into an answer since it wouldn't fit as a comment. But I guess this is a pretty good example of things you can do where public static variables are extremely useful and easy to use to store variables globally. Even if they aren't technically global since they belong to the classes, I still feel like they accomplish the same thing as a global variable would when used correctly.
I'll have to look at some of those other discussion posts a bit later to delve a little deeper into what kind of disadvantages there would be to using public static variables, but it seems to work fine for me.
Here I just wanted to give an example of how I use public static variables. For me they seem like the exact opposite of a rare case, and it's not hard to apply them properly.
I mean all these variables I listed are just from 2 scripts, I use a lot more public static variables than this and I use quite a lot of public static functions as well which generally just bring up an instance to the local stuff like:
//enemy script and when enemy dies it calls this:
if (XPUpdateBool == false)
{
XPUpdateBool = true;
PlayerXPScript.XPUpdateCall();
}
//on PlayerXPScript
public static PlayerXPScript XPInstance;
void Start()
{
XPInstance = GetComponent<PlayerXPScript>();
}
public static void XPUpdateCall()
{
XPInstance.XPUpdateFunction();
}
void XPUpdateFunction()
{
//tons of local code which only updates the global public static variables and playerprefs when changes occur.
}
You say you can't give a small example of what you can't do in C# but here's a pretty huge example of what you can do. I can't think of any easier way for me to use all these "global" variables throughout my project even if they aren't technically global. If I just have to take one extra step to type the name of the script in front of the variable that's not a big deal to me.
Nice examples. I tend to group my classes when using static variables and methods, so that they're a little more organised (for example, I might have a GUI class, which contains all the code necessary for defining the GUI, including any static members that might be related to it), but that's just an organisation issue, the fundamental concept is the same.
The whole point of what I learned here is that static
is global var - even though nobody says so. As I told you, reasons global var should be avoided as much as possible (which should be a damn lot) are not any where simple to explain (it's all already explained in the links) and will only begin to make sense once the project gets bigger. If you don't feel any problems using global vars, then it's just not big enough. Go ahead, keep using them. $$anonymous$$aybe you won't ever need to worry about all this.
Answer by cregox · Nov 14, 2013 at 09:42 PM
Wrong (thanks @SilentSin for this link). `static` is in fact a way of doing global var (in csharp). But it's the worst way.
Singletons are much better than static members. As the already linked link explains, using static members as global vars go against OOP.
This means once you set a static member you can't pass it around as an object. The more you use static as global var, the more difficult it is for unit testing / mocking classes.
But singletons are often abused, so be very careful when using them!
So...
**Toolbox** is probably the best work around for global vars:
public class MyClass : MonoBehaviour {
void Awake () {
Debug.Log(Toolbox.Instance.myGlobalVar);
Debug.Log(Toolbox.Instance.language.current);
// Optional: allows runtime registration of global objects
MyComponent myComponent = Toolbox.Instance.GetOrAddComponent<MyComponent>();
Debug.Log(myComponent.anotherGlobalVar);
Destroy(myComponent);
}
}
public class MyComponent : Component {
public string anotherGlobalVar = "yeah";
}
Hmm not sure if I understand your issue. I'm a pretty novice programmer only doing this for about a year and I never have a problem whatsoever manipulating variables in Unity with C#.
Whether using public static, public, or private, you can accomplish anything you need. If it's really that important you will likely have it as public static and save it permanently with a PlayerPref.
$$anonymous$$aybe I just don't understand the finer details of program$$anonymous$$g (I know I don't haha) but I really don't even understand what's the deal here.
Saving and manipulating variables and sharing them among all the scripts is the last of my concerns when it comes to difficult program$$anonymous$$g in Unity using C#.
@Ryan the good practices are meant for big projects. The bigger it becomes, the more evident they will be. Usually they are overkill for small ones. For instance, in Unity, if among all your scripts you have just 20 small classes or so, you shouldn't need to worry.
But I should probably elaborate this answer a little more, since you're here... There you go.
I could understand it being an issue if you are working with multiple programmers, I know on my current project having another programmer would be extremely difficult for me to coordinate all the variables.
But that's just really a problem of not fully understanding the entire scope of the project and all the scripts you are working on.
If you understand all your variables I think the standard variables will work just fine in conjunction with PlayerPrefs.
I'd be interested to hear more about your point since I'm always striving to gain more perspective and learn new things with program$$anonymous$$g, Unity, and game design.
$$anonymous$$y current project is around 50,000 lines of code but I have a very lose formatting style with lots of spacing, and have a TON of comments to help me remember everything. I'm sure a very good programmer could make my same project with much less code.
But still it seems that I never really have had any problems with the variables themselves. If you are meticulous and careful with your systems everything should work fine.
I personally think that it's a lot more difficult dealing with stuff like really good enemy AI and that kind of real time logic than the variables themselves. It can be at times difficult to use all my variables correctly for things like equipping armor from my inventory and it has to save all the different armor stats correctly and remember which slots are equipped etc. But that's more just a problem that I'm not smart enough to easily do it, the variables themselves are extremely easy to access I think.
Well, for a project to get really big you do need multiple programmers. But for it to get big enough so you'd worry, 1 programmer is enough. Specially if the project goes for years. You'll soon think yourself from past year as another programmer.
Understanding the entire scope of the project isn't a simple task. Understanding all your variables is not even doable for a big project. Being meticulous is good if you're dealing with limited resources. Even needed. Not the case for 99% of all projects out there today.
And I'd argue having tons of comments is actually a bad sign. If 25k of those 50k lines of yours are comments, you're probably coding too cryptic. The code should speak for itself, and it doesn't need to be $$anonymous$$imal at all.
Finally, boy, I'd love to get back on that "really good enemy AI" and out of this basic crap! :P
The issue as to whether static
members are a bad approach is one of personal preference more than anything else. It goes against the ideas behind OOP, but what's subjective is whether that's a bad thing. I won't deny, using concepts such as static
members incorrectly is bad, but the same can be said of a lot of OOP concepts, too. The fact is that static
members can be incredibly useful, and a lot of the work to avoid them because they "aren't proper OOP" usually ends up being a long-winded way to achieve more or less the same result. I, personally, see no point in that when there is a perfectly workable solution built into the language.
In cases like this, what is and isn't "good practice" is highly subjective, and you will find that the academic view of "good practice" is vastly different from the practical view of "good practice".