Search Unity

Reasons for using a Get Accessor instead of an If Statement in C#

Discussion in 'Scripting' started by segasega89, Oct 21, 2019.

  1. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    I'm a beginner to C# and I recently downloaded a Unity 2D platformer project off of Github. I'm trying to understand some of the coding inside of the project files for the player game object as I'm interested in learning how the physics in the game were created. The current bit of code that I'm trying to understand is shown below:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Movement : MonoBehaviour
    5. {
    6.     enum GroundMode
    7.     {
    8.         Floor,
    9.         RightWall,
    10.         Ceiling,
    11.         LeftWall,
    12.     }
    13.  
    14.     public Animator animator;
    15.  
    16.     public bool grounded { get; private set; }
    17.     public bool rolling { get; private set; }
    18.     public bool jumped { get; private set; }
    19.  
    20.     // General
    21.     public float standingHeight = 40f;
    22.     public float ballHeight = 30f;
    23.     private float heightHalf
    24.     {
    25.         get
    26.         {
    27.             if (rolling || jumped) { return ballHeight / 2f; }
    28.             else { return standingHeight / 2f; }
    29.         }
    30.     }

    I believe I'm right in thinking that the code is saying that if the player game object is jumping or rolling it will return the ballHeight variable divided by "2f"? Otherwise the value of standingHeight will be returned divided by "2f"?

    Can I ask why is a "Get Accessor" used in this case instead of just a simple if statement? For example:

    if (rolling || jumped) {
    heightHalf = ballHeight / 2f;
    }else{
    heightHalf = standingHeight / 2f;
    }

    Any helpful information would be much appreciated.

    Kind regards,
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    The main thinking on something like this is to wrap up some logic in a single "thing," on the premise that you might want this same piece of logic in multiple places in the program, and you would want it always to be identical.

    A getter is just a function that can be used "as if" it is a single variable, but what the compiler does is actually call the get{} method, run that code, and then stick that value into whatever expression you use it in.

    Same goes with set{} methods; you might want something special to happen every time another variable is changed, and one way to "hijack" that is to make a setter that a) sets the variable, and b) does the extra thing you want.

    Functionally it is identical to making a function called GetHalfHeight(), but this way it can be used where previously you just had a float called HalfHeight and now you want to make it this dynamic blob of code without changing any other places that use it.
     
    SparrowGS likes this.
  3. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Your if statement needs to be in a function somewhere in order be executed. The "get" is the function in this case.

    The code uses a C# Property, which runs the code inside the "get" block only when the property is accessed, and returns the resulting value. It's very efficient to only execute the logic when necessary. It's like calling a function for the result, but in the form variable.
     
  4. MattSawrey

    MattSawrey

    Joined:
    Feb 4, 2014
    Posts:
    13
    Get accessors aren't comparible to if statements. Get{} and Set{} accessors allow you to specify some control over how a property wihtin a class is accessed and written to. A get accessor is more akin to a function.

    So, within this movement class, you could have a function that returns the same value as this get accessor:

    Code (CSharp):
    1.  
    2.     float GetHalfHeight()
    3.     {
    4.         if (rolling || jumped)
    5.         {
    6.             return ballHeight / 2f;
    7.         }
    8.         else
    9.         {
    10.             return standingHeight / 2f;
    11.         }
    12.     }
    13.  
    ^That's a legitimate way to find the half height value within this class.

    You may, however, want to use a Get accessor instead, for a few reasons.

    One is simply cosmetic - they allow you to define a "property" of a particular class and keep a class' properties seperate from the logic of the class, which should be contained in functions. If you're thinking in an Object-Orientated way, you should think of a class' "properties" and get/set allow you to control how they're accessed and written to.

    Another is that you can pass parameters into a function, whereas you can't to the get or set accessors. They're a bit simpler in this regard, but this is because of their intended use - to define a class' properties.

    So, anything you can do with c#'s Get and Set accessors can be done with functions, but they're a neat language feature for simplifying code and thinking in an OO mindset.

    If statements are for controlling the flow of code and can be used within property get/set accessor, or functions.
     
    segasega89 likes this.
  5. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    First off, you need to realize that when someone shares their code it is indicative of the fact that they are a nice Person, not neccessarily a good programmer. Many of Unity's tutorials contain what I can only charitably call 'questionable' design choices and poor coding habits.

    Using an accessor as described above is usually very, very poor coding practice because you must know that the value returned when accessing this variable depends on other variables of that class, and nothing -- nothing!!!! -- in the place of the code where you are accessing the variable will show this.

    Consider
    Code (CSharp):
    1. float stepWidth = heightHalf * Speed;
    Nothing in that code above will indicate the direct dependency on the class' rolling or jumping attributes. It's phenominally bad codeing practice to do something like that. Errors introduced this way are near-impossible to find, and you should never have reason to doubt the behavior of what appears to be simple variables. Getters and Setters should be used only to validate or provide behind-the-scenes Management (e.g. Memory Management or persistance), never return different values or set other attributes. If you do something like that you should (as you correctly wonder yourself) pack it into a method, and call a method to return the variable value:
    Code (CSharp):
    1. float stepWidth = heightHalf() * Speed;
    or, even more explicit
    Code (CSharp):
    1. float stepWidth = heightHalf(this.rolling || this.jumped) * Speed;
    Yeah, the code is trash, but still the coder is a nice person for having taken the time to write and share it, so let's forgive the ugly code :)
     
    Last edited: Oct 21, 2019
    TadasTalalas and SisusCo like this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    That is one of the most profound things I've read today. This is a framing that everybody should be fully aware of. Thanks for putting it so succinctly.
     
  7. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Agree totally.

    However, I am less clear on this statement.

    A class offers an interface to the 'outside world'. That interface is all the caller need be aware of. It is explicit in OO that outside the class nothing should be known about its internal workings (the principle of information hiding).

    If the caller is dependent on the internal functionality of a class rather than its published interface, it is the calling code that is in question, not the class itself.
     
    angrypenguin and LiterallyJeff like this.
  8. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    @segasega89 The properties that you posted in your example are so-called Auto-Implemented Properties (C# Programming Guide).
    Code (CSharp):
    1. public bool grounded { get; private set; }
    This behaves like:
    Code (CSharp):
    1. private bool rolling;
    2.  
    3. public bool Rolling { get { return rolling; } }
    Why did the author chose auto-properties there? It is mostly a matter of taste. If you have a private class member which can be get from outside the class using a property, you might as well combine class member and property into an auto-property.

    One drawback to auto-properties is that Unity does not support displaying it in the inspector (last time I checked). When having class members that only matter at runtime, auto-properties could be one way to hide them from the inspector and save some time by using an auto-property.
     
  9. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    I would not only disagree with this, but strongly disagree with it. The entire idea of encapsulation relies on the fact that it isn't the calling code's business how HalfHeight is determined.

    Taking a common example, if I use an interface like:
    Code (CSharp):
    1. interface ICreatureLibrary
    2. {
    3.    Future<ICreature> GetCreature (string id);
    4. }
    Then I have no idea whether it's coming from a prefab that's already in memory, being loaded from an asset bundle, being dynamically created from the result of a server call, or what. And the fact that the calling code doesn't need to care, and can operate the same either way, is the primary benefit of using an interface like this.
     
    angrypenguin and LiterallyJeff like this.
  10. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Thanks everyone for giving me such helpful answers. It's a lot of information to absorb for a beginner so I'll do my best to acknowledge each answer in due course!

    I'm just trying to understand what Kurt is trying to explain to me above^. Are you saying that by using a Get Accessor instead of a GetHalfHeight function the HalfHeight's value will only change in that particular instance and wont change in other parts of the script? Sorry I'm finding it hard to understand what you trying to describe.

    Below I have tried to write a simple function that divides either the "ballHeight" and "standingHeight" float variables in half based on whether the player game object is either rolling or jumping.
    I'm just wondering if this simple thing that I've written is functionally the same as the original batch of code I included with my initial post? If it is functionally the same am I correct in saying that using a Get Accessor for the value of the heightHalf float variable in the original code instead of a GetHalfHeight function is shorter and cleaner? Could that be another reason for the original coder using a Get Accessor instead of a GetHalfHeight function?


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. public class Enemy : MonoBehaviour
    4. {
    5.     public float ballHeight = 30f;
    6.     public float standingHeight =40f;
    7.     public float heightHalf;
    8.  
    9.  
    10. void FixedUpdate ()
    11. {
    12.  
    13.      if rolling || jumping{
    14.  
    15.         heightHalf = GetHalfHeight(ballHeight);
    16.  
    17.      }else{
    18.  
    19.        heightHalf =  GetHalfHeight(standingHeight);
    20.  
    21.      }
    22. }
    23.  
    24.  
    25.  
    26. void GetHalfHeight(float heightToBeChanged){
    27.  
    28.     return heightToBeChanged/2f;
    29.  
    30. }
    31.  
    32. }
     
  11. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    One big difference is that you are updating "heightHalf" every FixedUpdate (50 times per second by default), where in the original example the value is calculated on-demand whenever the "heightHalf' Property is accessed.
     
  12. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    The most common reasons why people code in odd ways are 1) they heard somewhere it was "good style", 2) they're not quite sure what's needed and what's not, so put it all just in case.

    C# is just about the only language with get/sets (it was proposed earlier, but C# is the first language that wanted it). It's almost a signature. If you're writing a book, for example, and don't use them, someone could think "is this guy even writing C#?" Then with every book doing it, get/set everywhere is like peer pressure.
     
  13. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    As an example these two approaches are functionally identical.
    Code (CSharp):
    1. private float height = 10;
    2. public float HalfHeight {
    3.     get {
    4.         return height / 2;
    5.     }
    6.     set {
    7.         height = value * 2;
    8.     }
    9. }
    10.  
    11. // usage
    12. private void Start() {
    13.     // access the property, which runs 'get'
    14.    float fromProperty = HalfHeight;
    15.  
    16.     // set the property, which runs 'set'
    17.    HalfHeight = 5;
    18. }
    Code (CSharp):
    1. private float height = 10;
    2.  
    3. public float GetHalfHeight() {
    4.     return height / 2;
    5. }
    6.  
    7. public void SetHalfHeight(float value) {
    8.     height = value * 2;
    9. }
    10.  
    11. // usage
    12. private void Start() {
    13.     // get the halfheight
    14.     float fromMethod = GetHalfHeight();
    15.  
    16.     // set the halfheight
    17.     SetHalfHeight(5);
    18. }
    Properties are just shorthand for accessing variables via functions using a variable style syntax.
     
  14. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    Okay, I'm beginning to understand now why the Get Accessor was used instead of a function. I noticed in the original code that the Get Accessor was not placed in either the void start() or the void update() functions that are usually located at the top of C# scripts in Unity projects. Am I right in saying that they are usually placed outside these functions in scripts?

    I assume if a Get Accessor was placed in a void Update() function it defeats the purpose. And if it's placed in the void Start() function it will only be allowed to run once upon the script loading? So Get Accessors are used for efficiency ultimately...
     
  15. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    The 'get' and 'set' keywords can only be used inside a property definition at the class level. They are exclusive to properties. They are bound to the property name, and can only be used via the property name.

    The main advantage is that it allows you to use underlying functions without having to define and call two separate method signatures. You just use the one property as if it were a variable.

    From Microsoft:
    https://docs.microsoft.com/en-us/do...ng-guide/classes-and-structs/using-properties
     
    Last edited: Oct 22, 2019
  16. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    I believe that to be an astute observation. IIRC, JAVA was the first language that formally introduced setters and getters, and their use is hotly debated since then. But no 'serious' tutorial could afford to skip over that part, so everyone and their dog where treated to some contorted use case where people used Setters and getters without any real need - which probably explains why their use is so prevalent.

    Historically, on the C side of things, Setters and Getters were part and parcel of the ObjectiveC language, and no tutorial could ever be published without an entire chapter dedicated to setters and getters. This was of course because ObjectiveC grafted OOP onto the inherently non-OOP C language. Then (I believe around Version 2.0), the compilers for the ObjectiveC dialect started pushing the "@property" and "@synthesize" keywords that allowed to automatically use a variable declaration to be used as a class attribute. Behind the scenes, upon encountering the "@synthesize" keyword, the compiler generated the relevant setter/getter code. Setters and Getters were an important hook for the then nascent automatic garbage collection technologies, and likely that was where JAVA took its ceue to formalize them, since JAVA sported automatic GC (and the JAVA crators were inspired by some of ObjectiveC's features).

    C#, being a Microsoft attempt to snuff out JAVA, copied all of JAVA's features, including getters and setters. And of course the tutorials followed suit, giving s/getters a prominence way out of proportion for its coding significance (once you have automatic GC, edge cases aside there is next to no reason to use them), and today we have oodles of people who have that concept being rammed down their throats with insufficient explanantion when it's really appropriate to use them, and how to avoid common pitfalls when doing so. That may be a Major contributing factor as to why we see so many setters and getters in C# code today.
     
    Last edited: Oct 23, 2019
  17. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Stay on topic and don't get personal. Posts have been removed to clean up off topic bickering.
     
    Kurt-Dekker and LiterallyJeff like this.
  18. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Okay after a good bit of studying my basic understanding of how properties work is that a variable is declared within a class which is referred to as a "field" or "member value". So if I created a field called "experience" within a player class and then created a property for the field it would look as follows:



    Code (CSharp):
    1. public class Player(){
    2.  
    3.    private int experience;
    4.  
    5.    public int Experience(){
    6.  
    7.         get{
    8.      
    9.             return experience;
    10.      
    11.         }
    12.      
    13.         set{
    14.      
    15.             experience = value;
    16.      
    17.         }
    18.    
    19.  
    20.    }
    21.  
    22.  
    23. }//end of Player class

    And if I wanted to write a class in a separate script in my Unity project and create an instance of the player class shown above I can access the Experience property within the player class and change the value of the the property as follows:

    Code (CSharp):
    1. public class Game: Monobehaviour{
    2.  
    3.     void Start(){
    4.  
    5.         Player myPlayer = new Player();
    6.         myPlayer.Experience = 5;
    7.      
    8.  
    9.     }
    10.  
    11.  
    12. }
    What I'm wondering now is if I change the value of the "Experience property" in the code shown above am I also changing the value of the "experience field" that I initially created in the first coding sample shown at the top of this post?
     
    angrypenguin likes this.
  19. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    Yes indeed. The above example is exactly how it works, the de-minimus implementation.

    Now if you wanted interesting things to happen every time experience changes, you have already a central hookup point for it. Anywhere someone says foo.Experience = xxx, your setter will be called, which gives you a place to do other things relevant to experience changes, in this instance.
     
  20. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Could you be kind enough to provide an example where the getter of the Experience property would be called outside of the player class? As shown above in my previous code example I understand that the setter would be called if I create new instance of the player class and then change the value of the Experience property by writing "myPlayer.Experience = 5;".

    I'm just trying to think of an example where the getter of the property would be called outside of the class in a meaningful way...
     
  21. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    If all you want is changing (e.g. increase) the experience value from outside, you don't need the getter and setter. A simple 'public int experience' suffices.

    Code (CSharp):
    1. thePlayer.experience += 5;
    would still work.

    That's one of the reasons why the issue of setter/getter is so hotly contestet (and reason why I contend that you next to never really need an accessor).

    But imagine that every time you add experience, you wanted the class to check if your character Levels up. A setter *could* be used for this. I say that is a bad idea. Instead, create an 'AddExperience(int howMuch)' method to your class, and have all calculations done in that method - because if one setter causes a change in other attributes (e.g. Level), you are entering bugfest country.

    So there might be legitimate reasons for using setters and getters. Normal day-to-day use cases can get by without by simply using a 'public' declaration of the attribute.

    IMHO, of course.
     
  22. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Okay I understand where you're coming from and thank you for the helpful information but at the moment I'm trying to just understand how Get and Set properties can be used outside of their class. The reason for this is because - as mentioned in my original post - I'm trying to understand the coding of a Unity 2D platformer project that I downloaded off of Github. The person who wrote the scripts in the project uses a lot of properties and I'm just focusing on how to understand how properties work. Thanks for sharing your opinion on the usage of properties though - I'll definitely take account of what you've described above in the future.

    At the moment I understand how you can change the value of a property outside of a class by creating a new instance of a class and then calling the setter of the property as follows:


    Code (CSharp):
    1. Player myPlayer = new Player();
    2. myPlayer.Experience = 5;

    I'm just trying to figure out in what situation would the get accessor be called outside of its class.
     
    Last edited: Oct 24, 2019
  23. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    It sounds as if you're a little weak on classes in general -- not even counting gets/set. I'm saying that because member variables / fields are very basic things. You might look for a quick review of classes.

    That code -- others have mentioned this -- seems a bit odd, including the over-use of get/set. Maybe it's known to work just terrific and is worth sticking with, but you might do a fresh Search for "unity platformer demo". The Asset store has some, I think made by Unity. Something to consider: putting something on GitHub was at one point considered a resume booster.

    My list of how to read gets/sets:

    1) If you see
    public int cows { get; set; }
    cross off the back. It's exactly the same as
    public int cows;
    .

    3) That mess with
    bool jumped { get; private set; }
    is the same way -- cross off the back. The private makes it a little different, but it won't matter for reading the code.

    3) When you see
    public float goats { get { code to compute goats, then a return } }
    cross off the get. The inside looks like a function since it is. It's
    public float goats() { code to compute goats then a return  }
    (99% the same). HeightHalf is one of those.

    4) You very rarely see a real get and set together:
    int sheep { get {do stuff and return} set {do stuff and assign}}
    . It looks like 2 different functions, since it is. n=A.sheep; is like n=A.sheep.get(), and A.sheep=n; is like A.sheep.set(n);. The system figures out which one to call based on whether you're reading or writing.
     
    TadasTalalas likes this.
  24. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48

    My original post states that I'm a beginner to C#. The reason why I might be asking questions about "very basic things" is because I might be having trouble understanding these things even after watching a number of Youtube tutorials on how properties work and why they are useful.

    I've recently watched an official Unity Youtube video on properties shown here:


    The tutor in the video very clearly explains how a setter can be referenced outside of a class so that the field/member value can be altered. He uses a very simple example of how the field's value can be changed by referencing the properties accessor outside of its class.
    What I was wondering is whether someone could provide an example where the get accessor of a property would be referenced outside the properties class. I only ask so I can fully understand the basics of properties and why they are used.

    The code below shows how the Experience properties value can be changed to 5 by reference the set accessor below:

    Code (CSharp):
    1. Player myPlayer = new Player();
    2. myPlayer.Experience = 5;

    If I just referenced the Experience property in another class without trying to change it's value would that be considered an example of referencing the Experience properties get accessor? As I'm not trying to change the value of the Experience property, I'm only referencing it in code? I'm just trying to undertand iif the get accessor just returns the fields value how would the get accessor be used outside of the Player class?
     
    Last edited: Oct 24, 2019
  25. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    My apologies for being unclear. Setters and Getters are actually quite simple to understand if you look at the historic context, when object-oriented programming and Memory Management wasn't as simple as today.

    Setters and getters exist primarily to set and get the value of a property. This wasn't always as easy as it is today in C# for many arcane reasons. So people started out with a variable, let's say 'experience'. In order to access this variable from outside the class, they needed 'accessor functions': one to read the value, and one to set. So people usually did three things:
    1. defined the attribute, say an integer 'experience' and set up the UNDERLYING storage, say 'int _experience'. This will be where the data is stored
    2. created an accessor to read the value of the underlying variable. A method called 'int getExperience()'
    3. created an accssor to write/update the value of the underlying variable. A method called 'setExperience(int value)'
    Since this was so commonplace, people looked for ways to make this tedious work simpler. One way was to integrate code into the Compiler that automatically created the underlying variable, substituted an access to the attribute 'experience' with an invocation of the accessor getExperience(), and replaced an assignemt to the Attribute, e.g. 'experience = 5;' with an invocation of the setter 'setExperience(5)'. This is called syntactical sugar: it doesn't add new features, but it makes the code much more readable.

    Today, accessors still exist, but most of this code is autogenerated by the Compiler. In C# when you write
    Code (CSharp):
    1. public int experience;
    the Compiler behind the scenes creates an underlying store and autogenerate setter and getter. It then will invoke the (automatically generated) accessors to access that store. This is because the accessors are still important (in the back) and used for automatic Memory Management.

    In order to be feature complete, C# still allows you to add your own code that is executed every time you read or write to an attribute. That is what you code into the set and get clauses.

    when you write in C# today

    Code (CSharp):
    1. experience += 5;
    The Compiler will change that into

    Code (CSharp):
    1. int tempval = getExperience(); // execute the getter
    2. tempval += 5;
    3. setExperience(tempval); // execute the setter
    As you can see, for most intents and purposes, you can regard Setters and Getters as methods that get invoked every time you read (getter is invoked) or write (setter is invoked) an attribute. The big difference is that this is not reflected in the code you write, invocation of Setters and Getters is implicit, and can't be seen in the source. This can be a big advantage (you don't see all the Memory Management C# invokes for you when you do this), but also a big detriment (if an accessor has unwanted side effects).

    But to answer your question:
    • The setter is ALWAYS executed when you write to the attributre, even when you access the attribute from inside the class (but not if you access the underlying variable directly)
    • The getter is ALWAYS executed when you read the attribute, even when you access the attribute from inside the class, but not if you access the underlying variable directly.
    There really is no Magic nor Ninjas involved. The getter does exactly what it says, and so does the setter. In C# most of this is handled automatically for you if you declare a class attribute as 'public', but you can (if you want to) still Change the way the Default accessors work by providing your own underlying store, set: and get: methods.

    As you can see, C# already does a lot of this Set/Get stuff for you right out of the box when you create a 'public' attribute. The accessors still exist, but they are invisible to you, yet C# allows you to provide your own with Set: and Get: - but because C# already does such a great Job for you, you rarely need to provide your own.
     
    Last edited: Oct 24, 2019
    segasega89 likes this.
  26. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    Thanks very much for going through the trouble of typing out this helpful answer.

    So from what I understand after reading your post is that when I declare a variable in a C# script within a Unity project as follows:

    Code (CSharp):
    1. public int experience = 5;
    Behind the scenes of the C# script a get and set method is automatically generated by the compiler for the "experience" variable? Historically people would have to create the getter and setter accessor themselves but over time they figured out how to generate these accessors automatically behind the scenes? But C# still gives you the option of creating your own Getter and Setter accessors if you want to?

    What I'm wondering now is what is the advantage of being allowed to create your own Getter and Setter accessors for a particular field/member value if C# provides them automatically behind the scenes? Is it because by creating your own Getter and Setter accessors you can specify whether or not you want a particular field/member value to be read only or write only? Is it an OOP security thing?
     
  27. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    Yes. So:
    Code (csharp):
    1.  
    2. int ImFetchingDataFromExperienceGet = myPlayer.Experience;
    3.  
    That will fetch data from the get. If your get is just returning the private experience variable, then all you're doing is fetching the backing variable, which is standard.

    Code (CSharp):
    1.  
    2. get {
    3.  
    4.  return experience;
    5.  
    6. }
    7.  
    Quite a typical usage of properties is to have a get without a set. That allows things from outside your class to fetch values, but not to change values.

    Code (CSharp):
    1.  
    2. public int Experience {
    3.  get {
    4.   return experience;
    5.  }
    6. }
    7.  
    If that is the case
    Code (csharp):
    1.  
    2. //This will work
    3. int ImFetchingDataFromExperienceGet = myPlayer.Experience;
    4. //This won't work
    5. myPlayer.Experience = 5;
    6.  
    You could get it to return something else, though, it doesn't NEED to return exactly what the backing variable is

    Code (CSharp):
    1.  
    2. public int Experience {
    3.  get {
    4.   return experience * 10;
    5.  }
    6. }
    7.  
    Or you could have a public property with a different data type, and you can name it anything, like this:

    Code (csharp):
    1.  
    2. public string ExperiencePrint {
    3.  get {
    4.   return "You have " + experience + " experience points";
    5.  }
    6. }
    7.  
    In the example that you initially posted from the tutorial, there is no backing variable. It works the value out on the fly from other variables and it's not stored anywhere, and there is no set, because there is no backing variable to set. The ExperiencePrint is very similar. ~You could just write
    Code (csharp):
    1.  
    2. public string ExperiencePrint() {
    3.  return "You have " + experience + " experience points";
    4. }
    5.  
     
    Last edited: Oct 24, 2019
    sisus_co likes this.
  28. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    1) Accessibility. So a private backing variable with a public property that only has a Get. That can be read but not changed from outside the class.

    2) Future proofing. Let's say that you have a public variable. You write a bunch of code accessing and setting this public variable. Now you decide that you need to do something when this variable is set, or perhaps you need to validate what value it is being set to before you allow it to be set. Now you write a function that validates the input and sets the variable if it passes validation, and you make the variable private to make sure that everything on the outside needs to go through that function to set the variable. You have just broken all the outside references to that variable, because it's now private and inaccessible. If you had a default public property already setup and everything was referencing that and using it as a setter, then you wouldn't have broken any of those references. You could just add that functionality in the setter, and you wouldn't need to change any other code.

    3) Functionality. As the example above, perhaps when something is getting or setting a variable, you want to do something. You can do this with a function that gets or sets a private variable, or you do it with a property.
     
    segasega89 likes this.
  29. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    Not your fault, but adding "to C#" made it sound like you knew programming, but just not C#. That's probably what most people assumed. "I'm a beginner" might have been clearer. But not your fault.

    If you're new to programming, get/set is about the worse thing to start with. It's as if the first thing your Driver's Ed instructor did was adjust the sun roof and now you want to know everything about it before moving on to the brakes and steering.
     
    segasega89 likes this.
  30. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    There are legitimate reasons, but they are few and far in-between. That's why most people think that the use of accessors in the demo was excessive, perhaps even ill-advised. But every once in a blue moon you can come across a good reason to use them, and then they are really helpful:
    • I used an accessor to track down an really, really difficult to find bug. Some script reset my variable, and I needed to find out which. The set accessor, with a debug.Log() did the trick
    • As mentioned, when you want attributes that are read-only from outside the class (although there are other ways to do this)
    • Memory management was a classic for this, and for some times of games you may want to save some special variables whenever they change. A setter can help here.
    But you wonder correctly. Setters and Getters have diminished greatly in importance today; but because they are taught as if they were important, they are (as I feel) greatly over-valued and, accordingly, overused. Used without cause in tutorials, I feel they cause more harm than they do good. But that's my personal optionion.
     
  31. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    Did you mean to write { get; set; } after that?

    You're writing about how all C# business coders used write do-nothing gets/sets: int frog { get { return _frog; } set { _frog=value; }}. Right? Adding the { get; set' } rule was a shortcut. Is that an accurate summary?

    My memory of getters/setters is different. First came the idea of an interface and data-hiding. Maybe our class has a miles variable, or maybe kilometers, or maybe some new way to store distance. So we write getMiles() and setMiles(6) to handle it, and allow the real data format to change later. Miles felt like a virtual variable, and we started informally calling the pairs getters and setters.

    But then I think I agree with you that Java was the first big language to emphasize them. In the old days, everyone might know volume was always in decibels, which would never change, so public double decibels; is fine. Java said no-no, for consistency and safety, even that needs to be private with a get/set.
     
    angrypenguin likes this.
  32. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    You probably have some User Interface objects somewhere, such as a character sheet or progress bar. Those objects need to know the current experience value in order to display it. They could access it via the get accessor.

    This isn't correct? At best this is skipping over the whole concept of access modifiers - public, private, etc. But I don't think that going into such details is helpful for the OP here in any case.

    No. If a variable is public then any code can access it directly. No special functions are needed in order to do that.

    If something is protected or private then the compiler simply won't let other code access those things. (You do this to protect data from being accidentally modified when it shouldn't be.) However, in some cases you want to provide partial access, or to allow access that follows certain rules. Getters and setters can be used to do this.

    As I think Kurt already explained, though, getters and setters are just "syntactic sugar" on top of normal function calls. Aside from what they look like there's nothing special about them.

    Here's the important thing: the value in getters and setters isn't in just giving access to a variable. As @csofranz has said, if that's literally all you need to do then marking it as public gets the same job done. The strength of getters and setters it that they allow you to apply logic when doing so. Examples:
    • You can apply "snaity checks" to the values which you are applying in a setter. For example, your 'experience' variable probably shouldn't ever be negative. The setter can check that, and then either raise an error, correct the applied value, or both.
    • You can provide access to derived values. For instance, maybe you want to be able to display the percentage of progress towards your character's next level. You could write the math for this in every place you want to display it (not ideal!). Or you could have a separate variable which you update every time your experience changes (better...). Or, more simply, you could have a property which calculates it for you when you need it (probably better again, but depends on circumstances).
    • Perhaps you want outside code to be able to read your 'experience' variable, but you do not want them to be able to directly change it. You can make a property which has a getter but not a setter.
    Personally, I try to keep my getters and setters in properties to only do trivial things. This is because they look like variables, so I want them to mostly behave like variables. If they need to do anything significant, such as call other functions, I make them an explicit class method instead. The functionality is no different, this is just a signal to any other programmer using the code that "hey, this does more than you'd expect from a normal property".

    I'm going to respectfully disagree with this. Note that you also talked about having a "really, really difficult to find bug" where an unknown piece of code was resetting a variable. This could only happen because you made stuff public, and is one of the key reasons that keeping variables protected or private and accessing them via methods or properties is considered good practice. See the "sanity check" use case, mentioned above.

    You're right that it's not always necessary and that some people are unnecessarily strict about this, but I can easily see why it's taught as a reasonable default position.
     
    Last edited: Oct 25, 2019
    segasega89 and Doug_B like this.
  33. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    I assume that you're talking about a normal public variable which isn't a field/member value and that doesn't have a public property with get and set accessors associated with it?

    So lets say if I had a public int variable called "level" and I have another int variable called "experience" and I want the "level" variable to increase by 1 if the player in the game kills an enemy. If the player kills an enemy they receive 1000 experience points(hence the "experience" variable will equal 1000). I could have a function which checks if the "experience" variable has reached 1000 then the "level" variable's value increases by 1?


    I don't really understand this line. Which variable would I be making private?
     
  34. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    You'd write a function AddExperience(int newExp) which also handles the possible level increase. Then you'd hide level and experience to make sure no one accidentally adds directly to experience, getting it out-of-synch with level.

    That's basic OOP theory. There's a lot of bad stuff out there about OOP and encapsulation and data-hiding. But you can tell the good stuff since the examples will make sense right away.
     
    angrypenguin likes this.
  35. segasega89

    segasega89

    Joined:
    Feb 10, 2019
    Posts:
    48
    By hiding "level and experience" you mean making properties for both those variables and giving those properties get and set accessors respectively?
     
  36. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    Hiding, as in there's no way for anyone outside the class to directly use them. They work together and we don't want outsiders using them wrong. A longer example of how the class lets you do only what you need:
    Code (CSharp):
    1. void addExp(int newExp) // also increase level if needed
    2. void setLvl(int newLvl) // adjust exp to be that level
    3.  
    4. int getLevel()
    5. int getExpToNextLevel() // points needed to go up 1 level
    6. float getExpBarPct() // 0 to 1 percent of exp towards next level
    Those functions are all you need, and also all you're allowed to use. Inside, it might store only experience, computing level when you need it. Or it might store level and exp to next, but not the total exp. It doesn't matter, and we don't care, as long as the functions work.

    "First write the functions you want to have" is the most basic explanation of interfaces and encapsulation.
     
    angrypenguin likes this.
  37. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    No. Make them private, and then only provide functions that use them how you want them to be used. Sometimes this will include get/set properties, but don't assume that's always the case.

    For instance, if you don't want outside code to be able to set experience arbitrarily then don't give it a setter.