Search Unity

Public variable or Property?

Discussion in 'Scripting' started by omegabytestudio, Feb 15, 2017.

  1. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    So I got a quick one for you unity gurus :

    If I have an object in a script and I want other scripts to access it, I always wonder what is the best way to do it :

    Public :
    My favorite, but also disliked by most programmers. I can give a value directly in the editor and when the game load it should be faster then doing a getcomponent on start/awake (form what I have read). I also can access it just by typing the name. The issue most people have with public variable is that anyone can modify it without validation. it,s bad practice.

    Public property :
    With this, you don't have the issue of lack of validation. In your get/set of property, you can add code to validate your data. Sadly, it won't shup up in the editor, and you will have to getcomponent on start.

    I know everyone will tell me to no use Public variable. But then should I initiate every property on the awake/start component of my object? Won't it be a bit slower then public variable?

    Also is there another way to add a variable that can be used by another script and still show up in the editor?

    P.S : If anything I say in my post is wrong, feel free to correct it.
     
    blox5000 likes this.
  2. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,533
    You can use custom editors to expose property fields.
     
    omegabytestudio likes this.
  3. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    You can also use a combination of the 2

    Code (CSharp):
    1. [SerializeField]
    2. protected SomeType _Whatever;
    3.  
    4. public SomeType Whatever
    5. {
    6.     get
    7.     {
    8.         return _Whatever;
    9.     }
    10. }
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    There's a reason that public variables and public properties both exist in the C# language, and that is because sometimes you want one, and sometimes you want the other. If you have any sort of validation or reaction to a change of a variable, it should be a property. If you find yourself checking a variable in Update and then doing something if it changed, it should probably be a property. If neither outside scripts nor the inspector need write access to a particular thing, consider making it a property.
     
  5. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    @LaneFox

    Is that hard to implement? I might take a look on google later today, sounds great.

    If you enter your property value via the editor, it will bypass the get/set code right?

    @Mordus

    Good idea, but looks tedious to implement as I would have to repeat my variable each time.
     
  6. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    And is it a non-issue that I can't assign my property in the editor and have to do it via getcomponent?

    As I have a script manager that manage other scripts, and he need to be linked to every other script so I use public variable and set to value in the Editor.
     
  7. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,192
    There are ways to make it possible to assign properties from the editor. Either you create a custom editor from scratch or you use an existing asset to mostly automate the process. The Vexe Framework can handle properties and it's open source.

    https://github.com/vexe/VFW
     
    omegabytestudio likes this.
  8. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    You can also consider you can create public variables of the script itself. So a gameManager that has
    public PlayerScript player; Could have a player gameobject that has the script dragged and dropped in there, thus removing the need to use getComponent and you could then just access your properties through that.

    If it's a Public GameObject player and you dragged and dropped, you'd still have to create a reference to the script using getComponent.
     
    omegabytestudio likes this.
  9. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,533
    Custom Editors are pretty amazing. You can make it access whatever you want, property (get/set) or the backer field (bypass). They have a bit of a learning curve and serialization caveats and maintenance to consider.

    You could just expose the backer field as public if you really wanted to get it in the inspector. As long as you assume you're always going to communicate with it through the property at runtime...
     
    omegabytestudio likes this.
  10. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You can use [SerializeField] to keep a field private but allow it to be modified via inspector.
     
    Kiwasi, omegabytestudio and LaneFox like this.
  11. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    I wish there was a [SerializeAutomaticProperty] that would do the same as serialize field, but without me having to manually write out the private backing fields.
     
    omegabytestudio likes this.
  12. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,533
    Didn't realize that would make it popup in the inspector. Cool.
     
    omegabytestudio likes this.
  13. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    Shameful question : Can you use get/set like a property can?

    Code (csharp):
    1.  
    2. [SerializeField]
    3. string test;
    4.  
    5. public void test(string par)
    6. {
    7.    test = par;
    8. }
    9.  
    10. public string test()
    11. {
    12.    return test;
    13. }
    14.  
    It wouldn't work right? I don't have any to test it right now.

    It annoye me to right a class.gettest("blah"), when i can just do a class.etst = "bla";
     
  14. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,533
    I tried to understand this several times, but failed. So have some other code.

    Code (csharp):
    1.  
    2. [SerializeField]
    3. private string BackerField;
    4.  
    5. public string PublicField
    6. {
    7.    get { return BackerField; }
    8.    set { BackerField = value; }
    9. }
    10.  
     
    omegabytestudio likes this.
  15. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    Ahaha sorry about that, but your solution is what I was trying to do.

    Have a private variable works as a public field, except that i can add validation in the get set.

    I'm not a fan of dupping field (one private and one public) but if it's the only way. :)
     
  16. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    That's what you are doing anyway. The auto properties just hide it within syntactic sugar.

    There really is no explicit need to use properties. A field works fine. If you need validation, you can always change it later.

    This is best practice. For clarity, let's go over a bunch of them:
    • [SerialiseField] - Used whenever a variable needs to be exposed to the inspector.
    • public - Used whenever another script needs to access a variable.
    • Auto properties - Used whenever you need different access modifies on the set or get properties.
    • Explicit properties - Used whenever you need to get clever. For example data validation, triggering on change events, complex setting or getting behaviour.
    • Method - Used whenever there are additional side effects above and beyond setting and getting a variable.
    And there are a couple of bad practices you should stomp out mercilessly:
    • Using a public variable just to expose it to the inspector.
    • Using auto properties on everything, regardless of need.
     
  17. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
  18. Timelog

    Timelog

    Joined:
    Nov 22, 2014
    Posts:
    528
    Changing a field to a property is a breaking change. For example a field is a variable and can be passed by reference (ref or out keyword), while a property is a pair of accessors and cannot be passed by reference, thus changing a field that is passed by ref or out into a property will cause you code to break. So while you can change it later it might force some refactoring while changing a property to a field (or adding a backing field) will never be a breaking change.

    Also an interesting read from the VB team (same logic applies to C# as both compile to the same IL): https://blogs.msdn.microsoft.com/vb...-vs-fields-why-does-it-matter-jonathan-aneja/
     
    Last edited: Feb 16, 2017
  19. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,192
    You'd hate the code I write for non-Unity projects. :p
     
    mrwensveen likes this.