Hello guys !
i’v been using Unreal engine and Godot for years, but yesterday i wanted to try unity for the first time, one thing for me makes non sense, Setters and Getters
private int playerHealth;
public void HealPlayer(int Health)
{
// you can do anything here
playerHealth = Mathf.Clamp(playerHealth + Health, minHealth, maxHealth)
}
public void DamagePlayer(int Damage)
{
// you can do anything here
playerHealth = Mathf.Clamp(playerHealth - Damage, minHealth, maxHealth)
}
public int GetPlayerHealth()
{
// you can do anything here too
return playerHealth;
}
vs
private int playerHealth;
public int PlayerHealth
{
get
{
return playerHealth;
}
set
{
playerHealth = value;
}
}
also no one would do it like this way : PlayerClass.PlayerHealth += Health; ← this would be a bad design
what make you use the setters and getters and not the functions above ?
On major variables like Health it’s surely best to use such dedicated methods. But sometimes you have several, less important values you want to access and don’t wanna think and type full on method names like that.
Furthermore this is a way to have read-only variables. Just write “private” before the set{} and the property can still be read but not set externally. That is nice for variables that shall be used in formulas, like let’s say armor and damage values in an RPG. Having method calls for all those would feel like clutter.
So efectively you have the same control as with dedicated methods, but in a more compact form.
Raising events means just having other code in the setter and getter methods. Obviously you could also write that code in your dedicated methods.
However use that aspect very sparingly, because that leads to “unexpected side effects”. 98% of the time I set a variable or property, I do not expect “something else” to happen.
Most common code in setters and getters are validations. Like make sure that health cannot go below 0 for example. Or maybe throw an error in that case to catch a bug at setting player heatlh.
Well, whether PlayerHealth property is a good or bad practice notwithstanding, there’s one undeniable aspect about properties where you end up with much less code:
public int PlayerHealth { get; private set; } // read-only autobacked property
Or its alternative with a backing field ie for use with Inspector:
[SerializeField] private int playerHealth;
public int PlayerHealth => playerHealth;
Properties make most sense in a class when they encode some sort of “configuration”. They encapsulate public field access because public fields are notoriously difficult to refactor, or at runtime to monitor, to validate, to modify upon assignment.
The best practice is to use them for fast, no side-effects changes to a class instance. For instance, property setters should not call into various methods or make allocations.
Calling a method in C# otoh signals to developers that one should be wary of side effects and expect the call to be more resource intensive.
A better example for properties is for instance the address and port for a network connection class. You set those and then call Connect(), or if you don’t use the properies sensible default values will be used. Of course you could stuff all of that into the Connect() call but then you might end up with 5 or more parameters of which any one may or may not have to be set under every circumstance.
Properties make the code shorter, maybe easier to read, by letting you pretend you have a simple public variable. player1.health=100 can seem simpler than player1.setHealth(100);. Likewise if(player.1health<10) vs. if(player1.getHealth()<10).
You also get compound operations for free, like player1.health-=10; and player1.health–;. And using those is again shorter than player1.setHealth(player1.getHealth()-10). Of course, you could write changeHealth to reduce that to player1.changeHealth(-10);. But that’s still a little longer and the math -= version might be easier to read.
It’s not that big a deal. Properties were a thing when Java was written, but it decided not to include them and did pretty well.
They’re the same thing, they just look different. Under the hood they look pretty much exactly like the other examples you gave. It’s what’s often called “Syntactic Sugar”, a language feature that’s designed just to make the code look more tasteful to… someone.
As for why you’d use getters and setters more generally, rather than just making the variable itself public, it’s about scope control. The practical side of that is this: when there is a bug and you have observed that the value is wrong, how much code do you have to understand in order to first find out why, and then fix it without introducing any new issues?
While this is certainly true, I do feel that it’s worth pointing out that “less code” is not always a good thing. Under ideal circumstances your code will have the following properties:
It will operate as desired (i.e. it gets the right results in less-than-stupid time and there aren’t any bugs)
It is easy to understand (i.e. there are no hidden “gotchas” to someone new who is reading it)
It is easy to maintain (i.e. if I needed to change it, I wouldn’t need to touch lots of code to do simple things)
Sometimes shorter code helps with that. Sometimes it doesn’t. Sometimes it’s up to taste. Importantly, when you’re judging code, each of those things is of far higher priority than “could I make it shorter?”
The huge advantage of properties is that your consumers can just pretend the methods are variables, and treat them as such. Maybe this thing I am calling is a field. Maybe its a method. Maybe the program literally places a phone call to a holographic lizardman who lives in the sewers of the moon. The point is, as a consumer I don’t give a damn. That’s the beauty of encapsulation.
Getters and setters should be used when you need to do some extra work when receiving or assigning value.
Or if a field should be made readonly or write only.
If there’s no extra work, and no need for asymmetric access, there’s no need for getters/setters and you can use naked fields.
This.
When I use setter I want to indicate that some work is done and it might be good idea to make all the operations on local variable and than set a value.
When I use property setter this indicate setting underlying variable is very simple, and it is not a big problem to set value multiple times inside method.
Btw, I just learned about this today … just because Rider refactoring did it when changing a field to an auto-backed property. I immediately thought “what an odd bug” but then I noticed Unity compiled this just fine and looked around.
With at least Unity 2021.3 (maybe also some earlier versions) you can do this:
[field: SerializeField] public bool SomeSwitch { get; private set; }
This property will appear in the Inspector due to the “field:” prefix in the attribute which makes the autogenerated backing field serialized. Nice!
This should be a sticky on the forum and a blog post that has nothing else in it besides this code snippet!
But it looks as if the OP is comparing properties to explicit get/set functions. In their example they have HealPlayer, DamagePlayer and GetHealth. Those are doing the “extra work” that a property would (checking for min/max), and they work pretty well. In their world, you can use just a public field, or if you need more controlled access, you can write it up with real member functions.
Their Q, I think, is about why you’d want to convert a nice setter function like p1.HealPlayer(10) into an “ugly” property like: p1.health+=10.
I think that’s confusing to a native C# programmer since properties are emphasized so much. Even raw variable access is done through a {get;set} property, and for anything simple you obviously add code to that property. You almost never see a C# example with short accessor functions like the OP has.
The difference is that multiple functions are not bundled together as a single concept through language.
And a property exposes them as a single “value” to interact with.
Utility of either approach is a matter of opinion.
Propoerties were born in delphi, and IIRC one of the language designers is responsible for creatrion of C#, so they reused the concept.
In Delphi properties allowed you, for example, to resize a window without worrying about what is necessary to make this happen. You just set the value, and it will do the work. That was quite novel at the time.
In the end using and not using properties is likely a type of FizzBuzz problem, i.e. programmer’s trap.
By the way one of the reasons why properties wouldn’t be used in other engines is because sometimes underlying language does not have such concept.
There are no properties in C++, for example. As a result, when a need arise to create some sort of editor for values, engines usually introduce macros that declares properties for the sake of editor only. See UPROPERTY in unreal engine. That does not produce an equivalent of a C# property, however.
Not the same thing. That here, is an imitation. A frankenstein. It does not have all the features of a C# property, and often requires manual initialization, which defeats the point. Which is why people aren’t using such frankensteins in practice.
Also, people writing answers had forgotten that property can be read only, writeonly, or have getters and setters.
Properties are useful for making code less verbose and extending field behavior, but like almost everything they can be misused. For example, since getters are just functions they can have side effects or perform expensive work like any other function, but at glance they look no different than a plain field.
Unity’s own API is full of these kinds of not-so-dumb properties: there are basically no fields in UnityEngine.Object derived classes because they are all backed by native objects. Getters and setters are used to marshall data back and forth between C# and the native C++ objects, and something as simple as reading the name of an object can have unexpected performance implications.
I’ve never understood why the oft held, subtle, unstated default position that shorter code is better is a thing in 2022. In the 90s I got it, because we had very limited screen real estate and wanted to be able to see more stuff at once. And I get that going too far the other way is a pain, too.
I can’t remember the last time I had trouble with a piece of code just being too darn verbose. I do remember many occasions, particularly working in Unity, of being surprised at the complexity of operations hidden behind innocuous looking things in the name of being concise, or neat, or whatever.
One thing I like about the term “Syntactic Sugar” is that it reflects that, just as with real sugar, too much of it is bad for you.