I never use getter setters, am I bad? (C#)

So I am a reasonably experienced programmer. Over ten years of game programming experience spread out across personal projects, indie projects, and small team professional projects (1 to 4 coders). I don’t have a lot of experience developing HUGE enterprise systems where you have like a dozen or a hundred programmers working on the same code base, which may be where my not seeing the relevance of getter setters come from.

But I never use them. And in all my time programming, I’ve never once encountered an issue where I thought to myself ‘wow I wish I had used a getter setter there’. I am really kind of thinking, when working on small projects, or even 1-man indie game projects, whats the point? Except for typing more code and make things cluttered.

Can someone more experienced, or potentially more strict on this offer any specific examples of why and where you should have used a getter setter?

Now I’ve read lots of articles on this, I’ve been through the classes, I know the philosophy, encapsulation. But I tend to think programmers are a bit uncreative, and bound by tradition, or things that seem really formal or ‘program-ey’ or ‘tech-ey’ or ‘by the book’, and they like the idea of getter setters just because it makes it seem more formal and by the book. When really it’s not offering much advantage.

So I am just curious to know, when programming a game as 1 or 2 man project. Have you ever come across a point where you were like ‘fuck, should of used getter setters’?

2 Likes

Seems like you’re just procrastinating because you’ve discovered good reasons to use them.

Well me on the opposite, I’m relatively new to programming. I started programming with C# in Unity 2 years ago with no prior experience.

I sometimes struggle when I ask myself “should I use getter setters here?” I do like them because you can force lazy initialization, and you can add logic to avoid bad values getting returned/set, and all the other stuff you guys understand better then I :slight_smile:

But, being a junior programmer, I have royally screwed myself a few times by using getter setters in the wrong places, and saw my framerate drop like crazy…took me days to figure out why and where :slight_smile:

That said, I still use them a lot, mostly for encapsulation, even though I always conflicted (it’s best practice isn’t it?).

I’d love to hear some thoughts from experience programmers in the use of getter setters, like where/when they’re a must and vice-verca!

  1. just because your project is a 1 or 2 man project, doesn’t mean you should ignore standards because “you guys understand your own unique standards”… because what if you have someone else join later on? What if you try and share said code? (this is not a reason for properties though, just wanted to point it out).

  2. Properties

First, not all languages even have properties, and will instead insist on using methods/functions to do it. For instance Java insists on using functions with the shape ‘GetProp’ and ‘SetProp

...

private int _value;

public void SetValue(int value) { _value = value; }
public int GetValue() { return _value; }

...

Languages like C# on the other hand have explicit property constructs for the interface of your classes and structs. They still end up functioning similar to methods/functions, just with unique identifiers.

They’re useful for a lot of things.

properties of value types are immutable:
a property that returns a value type (like a Vector3) can not be modified directly. Because a property is like a function returning a result, and the result is a value type, you receive a copy of the underlying value. You can’t say:

obj.position.x = 5.0f;

because you’re modifying a copy. Instead you say:

var v = obj.position;
v.x = 5.0f;
obj.position = v;

Now, you might be thinking. UGH, that’s annoying! Why would I want that? Well… maybe you want to protect your value. Maybe that value you’re storing needs to be validated when setting. This leads me to the next…

properties can run code:
a property can run code when setting and getting. I can validate incoming values, or even have properties that are actually combinations of other properties and aren’t directly stored.

private float _radius;

public float Radius
{
    get { return _radius; }
    set { _radius = Mathf.Abs(value); //radius is validated as always positive }
}

public float Diameter
{
    get { return _radius * 2.0f; //diameter isn't an actual field, and this is actually a reflection of existing data }
    set { this.Radius = value; }
}

Encapsulation

That previous thing has to do with encapsulation. That’s an example of encapsulation. Encapsulation is useful so that you can control the state of an object through its class with out the rest of your code base really caring about such business. It’s only concerned about the shape of the interface of the class. As long as that is the same… it can keep working. Speaking of interfaces…

Interfaces

I screw a screw with a screw-driver. The Interface construct is for explicitly defining the interface of classes. Yes, the two uses of the words mean 2 different things. An Interface is the construct in which you explicitly define a castable interface type. An interface is the implicit shape of a class, all its in and out methods (properties and methods).

An interface can’t have fields, because fields are data. Interfaces don’t define data, they define interfaces. So an interface can only define the properties and methods of a class, not the fields.

Now the game community is notorious for writing “hack code”. In that we write code that doesn’t meet the normal standards out there. There’s a few reasons behind this, mainly because the designs of video-games don’t fit nicely into normal paradigms, and instead we hack apart existing paradigms to get it done.

This means that your non-use of properties isn’t necessarily “bad” in the context of what you do. But nor is it good.

Now all of this may not appear that important to you. But your design patterns may not every really use the power of these tools. And that’s fine. That’s the thing about foreign or unused tools… you don’t know get first hand knowledge of what they can perform until you go and do something first hand with them.

But some of us do use these tools to exact powerful design patterns. Yes these patterns could be accomplished just using Functions as well… ala Java. But of course we like consistency, and if something acts like a property, we want to access it like a property.

I use getters on my waypointmanager and guns scripts since I absolutely don’t want these values to be public, using a getter to return the bools usingWaypoint and readyToFire from their corresponding script seemed like a good idea.

That way I’m sure that they are always set by the code in their corresponding component and not me accidentally clicking it in the editor or some forgotten piece of test code that’s messing up my AI.

Just doing basic AI right now, but later on I got some vague ideas about more advanced AI types that will override the values, so will be using setter then for it since I still don’t want them to be public.

I guess I could just use Public functions to return the above values as well, but using a getter just “looks nicer” to me as well.

I had always heard that they were used to prevent people from hacking your variables

but i kind of always thought that if they can hack the variable then cant they just call the setter too

so i really only use them if i can use the setter more elaborately

in specific regards to unity most my variables i keep private because I usually just end up only changing them through local functions anyways
very rarely will I need another script to directly access a variable

even something as simple as apply damage i run through a script becasue i can use it to branch behaviors.

and I think the reason is in just about any case where you had an object that wanted to change an object or research it. (in a game instance anyways) you d want that action to just about always branch out into behaviors

Being on a amateur level I’m not aware of any (maybe because I haven’t ran into it yet) performance issues.
Could you give a example to help a fellow avoid the same trap, or is it a thing I don’t have to worry about since I do PC dev and it’s just something to take into account if doing mobile dev?

Getters/Setters are how you present your class to the world, making it a nicely sealed Unit. So when someone else uses it, they don’t have to afraid of breaking it, they don’t have to understand its inner workings. Or if you’re reusing those classes again you don’t have to be afraid of breaking it, nor do you have to bother remembering how you wrote it. If that doesn’t matter to you or your projects, then don’t use encapsulation.

This is a misconception I’ve seen many people have before.

Properties, and encapsulation in general, isn’t about security from hackers. When we say secure/strict code we mean that it’s up to safe standards so that other code that access it doesn’t break the functionality. ala what crazysi said.

Properties can have certain over heads.

  1. a property is a added call on the stack to access said property. Because it’s just a function really, you need to point at the function/prop, which then returns the field/data underneath.

  2. since a property can run code in itself, it could call other code, making it slower… but also necessary

  3. if the property is for a struct/value type, it returns a copy of the value, this means a copy must be made. If the struct is large, this copy can take a moment to create. In the same respect you shouldn’t be creating large structs, in this case the struct should become a class.

  4. All of this combined, and if called very frequently, can cause a lot of slow down.

This does not mean you should be prematurely forgetting properties because a bad design using properties has the possibility of being slow. It means you should understand the language you’re writing and how to understand why some things might get slow if you don’t design them correctly.

Hammer’s help you drive nails, but you can miss and smash your finger, but you won’t stop using hammers just because you smashed your finger a couple times. Instead you’d learn to aim properly.

heres a valuable piece of advice i learned in the professional ranks:

the end user never sees your code

Heres a story/joke that i also learned from a an extremely brilliant and highly accomplished programmer and engineer.

"so there’s 2 guys, a mathematician, and an engineer. they see this this smokin hot babe in a room that has a sign that says if you can reach her, you can have her…but with each step, you must halve the length of your strides. With that, the mathematician looks, and sadly leaves. the engineer on the other hand just starts marching into the room. The mathematician says “hey, you know you will never be able to reach her!” And the engineer says “yeah, but I can get close enough to do what i want with her”

in other words, if your code works, is easy to read, and is fast (enough) then who cares.

Thing is, it’s not always true that your end-user never sees your code.

What if I write code packages for the unity store… my users, the unity community, sees and interacts with my code.
Same goes if I’m releasing libraries of code out side of unity.
Or if I have a team of people.

I’m not saying one should follow strict rules.

I’m saying one must understand their own personal needs from beginning to end to make the choice for themselves and there is no broad general hooyah with a funny anecdote to tote.

And that’s some valuable advice I learned in the professional ranks.

I had a bunch of nice classes with get;set;

then I decided I wanted to be able to see the values in the inspector…

so now I dont bother with them.

Who cares? The guy who has to fix your bugs, or support your end user when things are blowing up. Always better to do things the “right way”, so everyone knows what is going on. Makes it easier to update or add new features, too.

The fact Unity won’t serialize properties or structures annoys the crap out of me.

I kind of understand why properties aren’t. The property may be complex, but if I flag the property as serializable… it should let me IMO.

As for structures, that’s just un-excusable.

IKR!

End of the day, once I finish with my scripts, ill most likely make most of that stuff private (I make alot of it public for now so I can fiddle)

you must of missed the first part of “it works” which means, all bugs were taken care of during development. while i agree that its good practice to leave code nice for the next guy, but this is a getter/setter…its not hard to understated.

The OP is writing a game, a game that only a few people will see the code. he is not writing an API where others outside his circle will see the code. API writing is a whole 'nother ball of wax. Other than that, sounds like you agree with me. I forgive you for no having a funny anecdote. :slight_smile:

So say you see this:

public float Speed = 0.0f;

Can I change this to set the speed? Yes or No? “its not hard to understand” after all.

This is why you’ve never seen the point, but it doesn’t mean there’s no advantage. Have you ever had bugs that resulted from someone shoving an invalid value into a public variable? A (well written) setter would have solved that, and ideally made the coder aware of their error (and the probable design or logic fault) which led to it immediately, rather than possibly leading to a subtle and hard to track down bug later. One such bug can potentially chew up more time than adding all of your getters and setters in the first place!

Even if you’ve never had that kind of error… if you or other coders on your team have to do checks on values assigned to exposed publics on your own, then you’re wasting time repeating effort which could have been done once inside a setter by the class author. Additionally, it’s an opportunity for inconsistency, and thus an opportunity for subtle bugs and something which will make code maintenance a nightmare because it’s scattered around (and probably done differently) instead of being in one place. Not to mention that this immediately blows away the idea that getters and setters lead to writing more code - as soon as you have to manual checks once outside of the class you’ve already written as much code as would likely have been in the setter in the first place. Plus, it impacts productivity by making everyone re-invent the wheel by having to consider the correct way to use public variables instead of centralising that by having the original designer write a setter which ensure that the right way is the easy way.

Even if you don’t think that’s an issue… requiring users of your classes and objects to poke around with their insides, even just through public variables, will generally lead your code to be much more tightly coupled than it needs to be. Thinking ahead of time about the interface, rather than just shoving “public” in front of things which other people may want to change, is likely to lead to better design which will also save you time later.

Even if you don’t think that’s an issue, there are cases where it’s a no-brainer for purely functional reasons. For example, need to fire an event whenever a value gets updated? Whack it in the setter and it transparently just works for everyone, including previously written code which uses it. For this reason it’s often considered good practice to wrap things in getters/setters/properties even when at first it seems that a public variable is fine (i.e.: any value is valid and it can be changed at any time without breaking anything) - it makes maintenance easier.

I know that low-level coders often look down on getters/setters/properties, and they do so quite understandably. When you’re writing a tight loop and want to optimise cache hits and so on, you don’t want to be making extra function calls to reach your data. But outside of high performance loops and similar areas of code, I’d personally use them almost all of the time - poorly designed or maintained code is likely to cost more in performance than badly designed code, and the time they save my team and I is time we can put into more features, polish or, if relevant (and it almost never is) optimisation where it actually counts.

As a direct answer to your question: As long as you get the job done you’re not “bad”. But if you’re wilfully overlooking tools which can help you get the job done then you’re needlessly making your life harder than it has to be.

You can write custom Inspector scripts for that. I admit that I’ve done that a grand total of once, though, and the vast majority of the time take the simple route of just marking things public and letting the auto-inspector do its thing. At the end of the day, while it does make code maintenance a little harder at times, that’s not usually a big deal because anything that needs to be changeable in the Inspector should be designed so that any possible input is valid input anyway, and I generally don’t want events or similar when those values change.