Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Beginners question about properties and why they are useful

Discussion in 'Scripting' started by segasega89, Jan 23, 2021.

  1. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Hi there,

    I've been trying to learn about properties over the last couple of days and although I sort of understand how to use them, I still don't understand why they are useful and why people are supposed to use them?

    For example in the below example I have created a "Properties" class that is situated within a Properties.cs file. I've created a private int variable that holds a value of 5 and a "Number" property that gets and sets the _number variable:


    Code (CSharp):
    1. public class Properties : MonoBehaviour
    2. {
    3.  
    4.     private int _number = 5;
    5.  
    6.     public int Number
    7.     {
    8.         get
    9.         {
    10.             return _number;
    11.         }
    12.  
    13.         set
    14.         {
    15.             _number = value;
    16.         }
    17.     }
    18.  
    19.  
    20. }


    In a separate C# script I've created a Player class where I create a handle of the Properties class shown above and then make an instance of the Number property and then output the value of the "_number" variable that's stored in the Property class:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Player : MonoBehaviour
    6. {
    7.     public Properties myProperty;
    8.  
    9.  
    10.     // Start is called before the first frame update
    11.     void Start()
    12.     {
    13.  
    14.         myProperty = new Properties();
    15.         Debug.Log(myProperty.Number);
    16.  
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.        
    23.     }
    24. }
    25.  
    I've been told repeatedly that it's good to use properties but I have no idea why in this example it is wise to do so? Can someone explain in simple terms why my example shows good practice? Why couldn't I just make the _number variable public and output it to the console instead of going through the trouble of creating a property with getter and setters? I don't understand why it is better practice to make that variable private?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Generally I prefer fields over properties but there is a bizarre fixation with "make everything properties" in the C# world, almost like a fetish without any actual reason to do so.

    The main difference is that with properties there can be separate get and set functions, and that lets you put code in instead of the simple example you show above.

    For instance, here's a way to "wrap" regular old variables and make them persistently stored to PlayerPrefs:

    https://pastebin.com/icJSq5zC

    Note in the usage examples in the top comments how the properties can just be used as regular old variables, but in actuality call code. That code could be as complex or as simple as you like.
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    In your example you should use a field, since it's accessing and setting a field without doing anything.

    The vast majority of the time we use properties, it's in order to have a value that can only be set internally, but can be read externally. Like:

    Code (csharp):
    1. public float CurrentVelocity { get; private set; }
    You probably want other things to know what the current velocity is. You probably don't want other things to set the current velocity of the object.

    A different example is if you want setting a value to have a side-effect:

    Code (csharp):
    1. private bool _missionFinished;
    2. public bool MissionFinished {
    3.     get => _missionFinished;
    4.     set {
    5.         if (value)
    6.             OnMissionFinished();
    7.         _missionFinished = value;
    8.     }
    9.  
     
  4. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921
    To add to this: skip properties. Put it at the very end of the list of things to learn. They're a bad combination of somewhat complicated, and they don't do anything. They're just a cutesy way to rewrite some functions. Programmers can be just as silly as everyone else and get caught up in unimportant stuff. C# has a lot of that, like "expression-bodied functions". They do nothing, but seem cool.

    The one reason to know something about properties is that Unity uses a few. A property can make it so a=b is really a function call
    a(b).
    For example the mesh class lets you do
    m.vertices=V;
    . It looks like a simple assignment, but it's actually doing complicated stuff You're really calling
    m.setVertices(V);
    . The property hides that from you.
     
    Kurt-Dekker likes this.
  5. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    There are different opinions about when to use them, as you might have guessed by the given replies.

    First of all, note that properties are just syntax sugar for plain old get/set methods. Perhaps you've seen those already. Properties allow you to write that kind of logic so that it looks like you were addressing a field.

    What are the benefits?
    They help to encapsulate the implementation details of your types. The most trivial implementation is the one you've shown here, and that's why they often appear to be useless - at first.

    But there's way more to it:
    - validation of assigned values / handling of "invalid" values
    - restricting or omitting access for read / write operations separately
    - storing the values in a different way internally ("hiding implementation details") or forward the call entirely to whatever provides the value internally
    - firing events (for example when a new value is set)
    ... probably more

    Next on the list: interfaces.
    Fields cannot be declared in interfaces. Here you'll usually pick up properties in order to declare which "values" are accessible, and it's the implementing type's responsibility to serve the values that are readable/writable through that "abstract access point".

    Next: debugging.
    It's difficult to debug a field. You'll either have to convert your field to a property for debugging purposes, do your job, and undo all of that. Or you need to track down all places at which the field is accessed, and go through a very inefficient trial&error routine in order to find the offending call site.

    With properties, you can just easily and quickly put a break point inside the property, add Debug.Logs there and it's all in that single place. From here, it's easy to check the current call stack when the break point is hit, or look at the stack that's provided in the log's stack trace.

    Downsides? The implementation you've shown is often seen as useless, and since properties often (not necessarily always) compile into methods, there's usually a method call involved.
    Does it matter performance-wise? In most cases you won't see a significant change. It can be critical when you have high-performance code, when you do heaving processing or have tons of accesses in tight loops with high iteration counts.

    Opinions you might also read on the internet: coding business applications vs game programming. Often enough, game programming is associated with "save all the performance you can" and this is often used as an argument against properties when they're not really needed. But honestly... if a game performs slowly, you can't really blame the use of properties.

    Personal preference:
    I generally do not expose fields, unless
    1) they're marked readonly
    2) it's a pure and simple type that primarily exists for passing data around
    3) it's a type that is used for critical processing.

    Though everything else follows clean encapsulation.
     
    Last edited: Jan 23, 2021
  6. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Interesting thread. I've never used them per se. All my gettable variables are public. Some are hidden in the Inspector if they're not needed for debugging or tweaking. All other variables are private. Methods are created as needed to set them, so I pass in the value like changeHealth(-10); but often I set them directly too...if things are well-organized, I see no problem doing that.

    All that said, I haven't worked with them (nor with interfaces) so my experience is only through reading. Maybe I'm missing out...
     
  7. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    The general idea is just to add some form of validation or restriction or change-events to modifying fields.
    Here's a pretty common example where properties can be used:

    You have two numerical values, "min" and "max":
    Code (CSharp):
    1. public float min;
    2. public float max;
    You want to restrict "min" so that it can never be greater than "max", and restrict "max" so that it can never be less than "min".
    With the way this code is currently setup, "min" and "max" can be set to any number, which is not ideal. To add these restrictions, you can wrap them in properties like so:
    Code (CSharp):
    1. private float min;
    2. private float max;
    3.  
    4. public float Min {
    5.    get => min;
    6.    set {
    7.       if(value > max) {
    8.          value = max;
    9.       }
    10.       min = value;
    11.    }
    12. }
    13.  
    14. public float Max {
    15.    get => max;
    16.    set {
    17.       if(value < min) {
    18.          value = min;
    19.       }
    20.       max = value;
    21.    }
    22. }
    23.  
    Now if, for example, the value of "max" is 50, and something tries to set the value of "min" to 70, the value will be capped to 50 instead.
     
    ZO5KmUG6R and seejayjames like this.
  8. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Nice example, that makes sense. Is it essentially the same as prohibiting direct changes and using a method to set values, just written differently (and more compact)?
    Though there's also the difference with Interface usability as mentioned above.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class forumPropertiesBasic : MonoBehaviour
    6. {
    7.     private float min = 0;
    8.     private float max = 100;
    9.  
    10.     public float getMin()
    11.     {
    12.         return min;
    13.     }
    14.     public void setMin(float arg)
    15.     {
    16.         min = Mathf.Min(arg, max);
    17.     }
    18.     public float getMax()
    19.     {
    20.         return max;
    21.     }
    22.     public void setMax(float arg)
    23.     {
    24.         max = Mathf.Max(min, arg);
    25.     }
    26. }
    27.  

    Static class version if you just want one global instance, and no need to attach to a GameObject:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public static class forumProperties
    6. {
    7.     private static float min = 0;
    8.     private static float max = 100;
    9.  
    10.     public static float getMin()
    11.     {
    12.         return min;
    13.     }
    14.     public static void setMin(float arg)
    15.     {
    16.         min = Mathf.Min(arg, max);
    17.     }
    18.     public static float getMax()
    19.     {
    20.         return max;
    21.     }
    22.     public static void setMax(float arg)
    23.     {
    24.         max = Mathf.Max(min, arg);
    25.     }
    26. }
    27.  
     
  9. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921
    All those things people say properties are good for are things functions in general can do. Because properties are just functions. It's like saying you should buy a classic camero because you can get to work with it, go to the store, or visit your mom.

    With mini/max we can have:
    void setMax(int m) { max=(m>=min)?m:min; }
    and use
    x.setMax(6);
    . It would go along with
    setMinMax(int lo, int high)
    .
     
    seejayjames likes this.
  10. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Yes. Properties are really just syntactic sugar for getter & setter methods.
    It's some pretty good sugar though - the same logic can all be condensed down to something like this:
    Code (CSharp):
    1. private float min;
    2. private float max;
    3.  
    4. public float Min { get => min; set => min = value > max ? max : value; }
    5. public float Max { get => max; set => max = value < min ? min : value; }
    Which is pretty nice. I've personally never really liked how much extra "filler" space getter/setters take up in other languages.
     
    Last edited: Jan 24, 2021
    Munchy2007 and seejayjames like this.
  11. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Now I'm probably going too far astray...here's a similar idea implemented as a class, just wanted to compare the approaches. This allows you to instantiate "int range" objects; the constructor has arguments for the the initial, min, and max values. Note: does not derive from Monobehaviour, so it just resides in Assets.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class forumIntRangeClass
    6. {
    7.     int value;
    8.     int min;
    9.     int max;
    10.  
    11.     // Constructor
    12.     public forumIntRangeClass(int valueArg, int minArg, int maxArg)
    13.     {
    14.         value = valueArg;
    15.         min = minArg;
    16.         max = maxArg;
    17.         checkRange();
    18.     }
    19.     public int getValue()
    20.     {
    21.         return value;
    22.     }
    23.     public void setValue(int setValueArg)
    24.     {
    25.         value = setValueArg;
    26.         checkRange();
    27.     }
    28.     void checkRange()
    29.     {
    30.         value = (value < min) ? min : value;
    31.         value = (value > max) ? max : value;
    32.         Debug.Log("value " + value);
    33.     }
    34. }
    35.  

    Then to instantiate and access them (this one derives from Monobehaviour, so put it on a GameObject):


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class forumIntRangeClassAccess : MonoBehaviour
    6. {
    7.     forumIntRangeClass myIntRange;
    8.     void Start()
    9.     {
    10.         myIntRange = new forumIntRangeClass(80, 50, 100);
    11.     }
    12.  
    13.     void Update()
    14.     {
    15.         if (Input.GetKeyDown(KeyCode.R))
    16.         {
    17.             // some will be in the allowed range, others will be clamped to (50, 100)
    18.             myIntRange.setValue(Random.Range(0, 200));
    19.         }
    20.     }
    21. }
    22.  
     
  12. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I've done something similar for my "universal" assets, though I split the logic into two different structs, "IntRange" (contains the min/max values) and "ClampedInt" (contains a value clamped within an "IntRange").
    Code (CSharp):
    1. [System.Serializable]
    2. public struct IntRange {
    3.   [SerializeField] private int _min;
    4.   [SerializeField] private int _max;
    5.  
    6.   public IntRange(int min, int max) {
    7.     _min = Mathf.Min(min, max);
    8.     _max = Mathf.Max(min, max);
    9.   }
    10.  
    11.   public int GetRandomRange() => Random.Range(_min, _max + 1);
    12.  
    13.   public int ClampValueInRange(int value) => Mathf.Clamp(value, _min, _max);
    14.  
    15.   public bool IsValueInRange(int value) => value >= _min && value <= _max;
    16.  
    17.   public int Min => _min;
    18.   public int Max => _max;
    19. }
    Code (CSharp):
    1. [System.Serializable]
    2. public struct ClampedInt {
    3.   [SerializeField] private int _value;
    4.   [SerializeField] private IntRange _range;
    5.  
    6.   public bool IsValueMin => _value == _range.Min;
    7.   public bool IsValueMax => _value == _range.Max;
    8.  
    9.   public ClampedInt(IntRange range, int value) {
    10.     _range = range;
    11.     _value = _range.ClampValueInRange(value);
    12.   }
    13.  
    14.   public ClampedInt(int minRange, int maxRange, int value) {
    15.     _range = new IntRange(minRange, maxRange);
    16.     _value = _range.ClampValueInRange(value);
    17.   }
    18.  
    19.   public void MinimizeValue() => _value = _range.Min;
    20.   public void MaximizeValue() => _value = _range.Max;
    21.  
    22.   public int Value { get => _value; set => _value = _range.ClampValueInRange(value); }
    23.  
    24.   public IntRange Range {
    25.     get => _range;
    26.     set {
    27.       _range = value;
    28.       _value = _range.ClampValueInRange(_value);
    29.     }
    30.   }
    31. }
    The reason they're separate is purely because sometimes there are cases where I only require just the range of values.
     
    seejayjames likes this.
  13. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921
    Sure. The basics of OOP is information-hiding or encapsulation. It's at least a 40-year-old concept. The variables in a class either have some non-obvious relationship (like min must be <= max) or are complicated (maybe you store only the minimum and the range), or have special restrictions (must be positive) or you expect to rewrite them at some point.. So you hide those, and expose what you want in the interface (all public functions). Way, way back C even had you make a file with _only_ the function headers. That was all you needed to see to use the function.

    Properties tend to focus thinking on the actual private variables which I think makes designing the interface harder. Like with a range class we might like getters for: min, max, midpoint and range (distance between min and max).. And also things like setRange(min, max) and growRangeToInclude(n). Thinking "well, the private variables are min and max" (or something else) is a distraction from that.
     
    seejayjames likes this.
  14. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Thanks for the helpful reply!

    My understanding is that if you declared a variable with a public access modifier in a script you could access the variable from another script using code.
    However you wouldn't be able to decide whether this variable could be read-only or write-only. When you declare a variable publicly it's automatically readable and writable from outside its class.
    But I'm wondering what advantage does making a variable read only or write only have? Why is it a good thing to not just have it readable AND writeable from the very beginning when you create it in order to access the variable from an outside script?

    You say that you can put complicated code within the get and set accessor of a property but I'm still trying to figure out what advantage does that system have over just make a variable public from the very beginning and getting access to that variable with code?
     
  15. ZO5KmUG6R

    ZO5KmUG6R

    Joined:
    Jul 15, 2010
    Posts:
    490

    I can say that functions like this get so annoying when you've used an asset that solely does that.

    Code (CSharp):
    1.     public IEnumerable<Wheel> GetGroundedWheels()
    2.     {
    3.         if (Controller.getAxle(0).getLeftWheel().hasContact())
    4.             yield return Controller.getAxle(0).getLeftWheel();
    5.         if (Controller.getAxle(0).getLeftWheel().hasContact())
    6.             yield return Controller.getAxle(0).getRightWheel();
    7.         if (Controller.getAxle(1).getLeftWheel().hasContact())
    8.             yield return Controller.getAxle(1).getLeftWheel();
    9.         if (Controller.getAxle(1).getRightWheel().hasContact())
    10.             yield return Controller.getAxle(1).getRightWheel();
    11.     }
    Just starts looking really, really ugly..

    Plus, properties are also just really nice for small things, where you could use a field and set it each frame.

    Code (CSharp):
    1. public bool IsPoliceCar => Siren.Lights.Count > 0;
    2. public bool BrakeLightsOn => tailLight != null && tailLight.activeSelf;
    3. public bool ReverseLightsOn => reverseLight != null && reverseLight.activeSelf;
     
  16. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    I'm a bit confused about the way you've created these properties as they seem to use syntax that is different from how I learned to make properties in Unity.

    For example you have written a private float for the min value and its associated property like this:

    Code (CSharp):
    1.  
    2. private float min;
    3.  
    4. public float Min {
    5.    get => min;
    6.    set {
    7.       if(value > max) {
    8.          value = max;
    9.       }
    10.       min = value;
    11.    }
    12. }
    Whereas the way I learned to create properties is like this:

    Code (CSharp):
    1.  
    2.  
    3. private int _number = 345;
    4.  
    5.     public int Number
    6.     {
    7.         get
    8.         {
    9.             return _number;
    10.         }
    11.  
    12.         set
    13.         {
    14.             _number = value;
    15.         }
    16.     }
    Is " get => min;" a short way of writing:


    Code (CSharp):
    1.      
    2.  
    3.         get
    4.         {
    5.             return _number;
    6.         }
     
    Vryken likes this.
  17. ZO5KmUG6R

    ZO5KmUG6R

    Joined:
    Jul 15, 2010
    Posts:
    490
  18. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    You can also do the same thing with methods. These are equivalent

    Code (csharp):
    1. public int GetMin() {
    2.     return min;
    3. }
    4.  
    5. public int GetMin() => min;
    For getters and setters that does easy things, it helps a lot with reducing line count, especially if you are a dirty heretic that puts the opening brace on a new line.

    /s
     
    segasega89 and print_helloworld like this.
  19. print_helloworld

    print_helloworld

    Joined:
    Nov 14, 2016
    Posts:
    231
    Just use properties when you believe theyd help making your code simpler and easier to understand (in any context).
    And yeah that's fine if you dont, since you can always learn the applications later on overtime.
     
  20. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    This ^ ^ ^

    Except I would say, "just use (ANY TOOL) when you believe they'd help making your code simpler and easier to understand."

    Just say "no" to resume-driven coding.
     
    print_helloworld likes this.
  21. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Exactly.
    In C#, you can use the "arrow expression" with functions that are one-line long as a shorthand way of writing them.
    They can be used in properties, methods, and constructors.
    All of the following examples do the same thing:
    Code (CSharp):
    1. private int myInt1;
    2.  
    3. public int MyInt1 {
    4.    get { return myInt1; }
    5.    set { myInt = value; }
    6. }
    7.  
    8. //////////////////////////////////////////////////////////////////////////////
    9.  
    10. private int myInt2;
    11.  
    12. public int MyInt2 { get => myInt2; set => myInt2 = value; }
    Code (CSharp):
    1. void IncrementScore1() {
    2.    score++;
    3. }
    4.  
    5. //////////////////////////////////////////////////////////////////////////////
    6.  
    7. void IncrementScore2() => score++;
    Code (CSharp):
    1. float CalculatePercent1(float numerator, float denominator) {
    2.    return numerator / denominator;
    3. }
    4.  
    5. //////////////////////////////////////////////////////////////////////////////
    6.  
    7. float CalculatePercent2(float numerator, float denominator) => numerator / denominator;
    It's just even more syntactic sugar.
     
  22. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921

    But it's also an example of how properties are nothing. Your original code (with the get's removed):

    Code (CSharp):
    1. if (Controller.axle(0).leftWheel().hasContact())
    2.   yield return Controller.axle(0).leftWheel();
    Rewritten with properties instead of functions looks about the same:

    Code (CSharp):
    1. if (Controller.axle(0).leftWheel.hasContact)
    2.   yield return Controller.axle(0).leftWheel;
    That example of properties and the very silly "expression-bodied" syntax also seems like nothing. The original:

    Code (CSharp):
    1. bool IsPoliceCar => Siren.Lights.Count > 0;
    Rewritten as a plain old function seems just fine:

    Code (CSharp):
    1. bool IsPoliceCar() { return Siren.Lights.Count > 0; }
    The first way is a little less typing. But it's not like the limit on programming is how fast we can type it.
     
  23. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    The limit always seems to be "how fast can I debug it?"

    All these new-fangled ways of being a clever programmer monkey and cramming 57 things into one statement only means you are slowing me down when I have to rewrite your code because something deep inside there blows up once in a while.

    System.Linq baby, I'm lookin' right at you especially, with your silly:

    this(is).what(im).talking(about).and(it).had(a).null(reference).and(blew => up).somewhere(who).knows();


    Just ... don't. Please.
     
  24. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    I now know how to use an expression body to make the code of a get accessor within a property shorter and more tidy but is it possible to use an expression body with the set accessor like the one shown below?:

    Code (CSharp):
    1.         set
    2.         {
    3.             _firstnumber = value;
    4.  
    5.         }

    How would I go about using an expression body to shorten this snippet of code?

    EDIT: Apologies, someone above explain that you could write the following to shorten the code:
    Code (CSharp):
    1. set => _firstnumber = value;
     
  25. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    You say in this example that I might want a method/function to know what the current velocity is but at the same time I might not want functions to be able to change the value of this particular variable.

    I'm trying to understand what kind of scenario would I be in were I would go through the trouble of privately setting the velocity variable in order to prevent a function from trying to alter it?

    Couldn't I just make sure that I create functions in my project that explicitly don't alter the value of the velocity variable? If I knew what I wanted to do in a project how would I accidentally go about creating a function that alters the velocity variable when I know from the start that I'm trying to avoid altering this variable?
     
  26. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    Also I'm just wondering could you explain what the following code you've written means here:


    Code (CSharp):
    1.  
    2.  
    3. private bool _missionFinished;
    4. public bool MissionFinished {
    5.     get => _missionFinished;
    6.     set {
    7.         if (value)
    8.             OnMissionFinished();
    9.         _missionFinished = value;
    10.     }
    11.  
    I understand what the get accessor is doing but I'm not sure what you're saying in the conditional that is contained within the set accessor? Are you saying that if the value of the variable is set then execute "OnMissionFinished()"?
     
  27. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    "_missionFinished" is a
    bool
    type, so
    value
    is either true or false.
    if(value)
    is exactly the same as
    if(value == true)
    .
    Likewise,
    if(!value)
    is exactly the same as
    if(value == false)
    .
    Any
    bool
    type can be compared this way.
     
  28. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    Usually because you've got other people on the team you want to communicate to that "this script assumes that the variable is only changed internally". Alternatively, you want to communicate it to yourself in like two weeks when you've forgotten the details.

    But, yeah, you could totally just remember to not set the thing from somewhere external and let it be public. Lots of people would advocate that style - see the entire Python community*.

    Yeah. The example is a bit contrived, finishing missions is probably a big enough deal that I'd use a method. A better example would be something like

    Code (csharp):
    1. public bool Active {
    2.     get => _active;
    3.     set {
    4.         if (_active != value) {
    5.             _active = value;
    6.             UpdateUI();
    7.             // or
    8.             OnActiveChanged();
    9.         }
    10.     }
    11. }

    * Don't actually take any advice from the Python community.
     
    segasega89 likes this.
  29. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    Okay so Mission Failed is a bool which means it equals either true or false.
    In the set accessor it's saying that if MissionFinished is true it should execute the OnMissionFinished() function.

    But why after it executes this function does it then say "_missionFinished = value;"? What is the purpose of this line?
     
  30. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Haha I'll take your advice regarding the Python community. I feel that I'm understanding it all a bit better now.

    Can you recommend some sort of practical exercise that can help me practice the use of properties etc? Like a particular project I could try to make in Unity?

    Maybe I should look on Youtube for some sort of exercise that involves the usage of properties in a way that shows how valuable they can be.
     
  31. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,196
    Not really, no. They're just there to enable a slightly more terse syntax at times, they don't do anything special.
     
    Suddoha and segasega89 like this.
  32. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    To actually set the value of the "_missionFinished" field.
    Without that, the field will remain as it's current value.
    The "value" keyword in a property only represents the incoming value to set.

    Here's the equivalent of a setter-function:
    Code (CSharp):
    1. private bool _missionFinished;
    2.  
    3. public setMissionFinished(bool value) {
    4.    if(value) {
    5.      OnMissionFinished();
    6.    }
    7.  
    8.    _missionFinished = value;
    9. }
     
    Last edited: Jan 26, 2021
  33. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,921
    Properties are awesume that way. The first four(!!) responses to "why are properties useful" were that properties are just fluff, but the OP is now jazzed about them. They're like guardians -- "I'm going to learn how to write code for... ooohh, properties. Shiny!"