Search Unity

Are public variables a good practice?

Discussion in 'Getting Started' started by hubot, Mar 26, 2016.

  1. hubot

    hubot

    Joined:
    Mar 6, 2016
    Posts:
    13
    I've some doubts for using public variables in Unity projects. In my opinion it's a bad practice. Why are you use public variables? Isn't a better solution use public properties instead of public variables? What are you think about this?
     
  2. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,205
    You can't serialize properties. Thus in the following example Health will be modifiable in the Inspector but Mana won't.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Entity : MonoBehaviour {
    5.     public int Health;
    6.  
    7.     public int Mana
    8.     {
    9.         get;
    10.         set;
    11.     }
    12. }
    You can bypass this limitation by serializing the private variable but at that point it may as well have been public.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Entity : MonoBehaviour {
    5.     public int Health;
    6.  
    7.     [SerializeField]
    8.     private int _mana;
    9.     public int Mana
    10.     {
    11.         get
    12.         {
    13.             return _mana;
    14.         }
    15.         set
    16.         {
    17.             _mana = value;
    18.         }
    19.     }
    20. }
     
  3. Freakyuno

    Freakyuno

    Joined:
    Jul 22, 2013
    Posts:
    138
    They are all variables...you're talking about the difference between a "property" and a "field".

    You're also correct about the typical practice, but as @Ryiah points out, Unity can't inspect properties at Editor Time for some reason, so to expose a variable to the Unity Editor it needs to be a field.

    For the most part, in modern day c# the differences between the two internally have gotten really small, the major component being the pattern. As a pattern, properties can provide for long instantiation, failed instantiation, or even throwing an exception where fields should always be fast, and never throw an error when setting them.
     
    JoshSims likes this.
  4. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,205
    Technically you can if you write a custom inspector script that is specifically set to do it, but the reason it cannot do it by default is that property getters/setters can have side effects (they're made for runtime after all and not edit time).
     
    JoshSims, jhocking and Kiwasi like this.
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    In general you should make everything private unless you have a reason to do otherwise.
     
    JoshSims, landon912 and jhocking like this.
  6. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    This whole issue is actually why I use [SerializeField] with private variables, not public variables which I see most people do. I need to be able to serialize the variables in Unity, but I don't want them to be public variables, exposed to other code.

    EDIT: Just saw
    Nonsense, the variable is still private. I know for sure it isn't modified or used by any other code.
     
    Kiwasi likes this.
  7. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,205
    Mutator methods (weird name for a setter if you ask me) are about controlling changes to a variable. Exposing a private variable will allow you to change the contents but the mutator won't run. If you need to access the property you're better off with a custom inspector since that can be made to call a mutator.
     
  8. Freakyuno

    Freakyuno

    Joined:
    Jul 22, 2013
    Posts:
    138
    Yep, this is exactly correct. I think the confusion is, most people have gotten used to seeing something that looks like this:

    Code (CSharp):
    1.         public string MyVariableA { get; set; }
    2.         public string MyVariableB { get; set; }
    The confusion is, that this is just the compiler interpretation making it easier on us, because it's still generating the private field backings for us. So if you were to look at the disassembled code you'd see:

    Code (CSharp):
    1.         private string _myVariableA;
    2.         private string _myVariableB;
    3.  
    4.         public string MyVariableA
    5.         {
    6.             get
    7.             {
    8.                 return _myVariableA;
    9.                
    10.             }
    11.             set
    12.             {
    13.                 _myVariableA = value;
    14.             }
    15.         }
    16.         public string MyVariableB
    17.         {
    18.             get
    19.             {
    20.                 return _myVariableA;
    21.             }
    22.             set
    23.             {
    24.                 _myVariableB = value;
    25.             }
    26.         }
    It's going to get even funnier now with object accessors (which are new to C#), and going to confuse things a little further, because now you can do something like this:

    Code (CSharp):
    1.         private string _myVariableA;
    2.         private string _myVariableB;
    3.  
    4.         public string MyVariableA => _myVariableA;
    5.         public string MyVariableB => _myVariableB;
     
    Deleted User and Ryiah like this.
  9. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,205
    Oh joy. I had just gotten used to the first shortcut. :p
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Oh nice. Does this work in Unity's version of Mono? I'm not at my computer to try it. And can you do it and still modify the access to get and set individually?
     
  11. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,205
    Unity 5.3.4f1 does not seem to like it.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Foo : MonoBehaviour {
    5.   private int _health;
    6.  
    7.   public int Health => _health;
    8. }


    Visual Studio 2015 Community Update 1 gave an additional error message.

    Error CS8025 Feature 'expression-bodied property' is not available in C# 4. Please use language version 6 or greater.
     
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Fair enough. I figured it was a pretty new feature.
     
  13. Freakyuno

    Freakyuno

    Joined:
    Jul 22, 2013
    Posts:
    138
    Yea, it'll probably be a little while before unity supports c# 6.0 I'm guessing.