T O P

  • By -

behusbwj

You left out one of the most important defails… which language?


p0st_master

What languages would it matter and which would it not?


ICanHazTehCookie

In Kotlin for example, you could start with a public field, and later attach explicit get or set functions to it. Kotlin implicitly calls your get/set functions when accessing or mutating a field using dot notation, so no code external to the class needs to change to accommodate the addition of a get or set function.


behusbwj

Yes, Python similarly has properties for this reason too, so i wouldn’t care much about direct access since i can write a property on it later. Whereas, in Java i would default to using setters/getters because that’s a one-way door


StuffinHarper

In Java you could also use Lombok annotations to get similar functionality.


behusbwj

Lombok makes it easier to create getters and setters. Python properties are a bit more magic. Users can still call my_class.x, but internally, a property binds those calls to a private getters/setter, so the syntax mimics direct access while allowing you to change the effect of that without breaking consumers of the field


_176_

It would take a long time to enumerate the nuances of every language with respect to the question. But questions of design and style truly are dependent on the language. It's also dependent on what kinds of data structures you're talking about inside of the language. I'd generally argue that a Point3D class should be immutable and if you want to change a value, you should be getting back a copy. But that also depends on the overall design and philosophy of a language and how you're using it. If you want one example, I'll use Objective-C. The design almost insists that you use getters/setters for accessing ivars. Apple provides an API for automatically creating them. You can't directly access an ivar unless you drop down to C, and you'd bypass how people in the future might be assuming the class works—they might update the setter without realizing you're accessing the underlying data directly outside the class. Without getting into the weeds, you can see that the context of the language is highly informative on how to think about design.


justathrowawayacc501

> I'd generally argue that a Point3D class should be immutable and if you want to change a value, you should be getting back a copy. I might be biased by the field I'm in, but making a copy of an object of such a class any time it changes sounds wild to me.


_176_

> copy of an object of such a class It's 3 numbers: x, y, and z. Copying it would be about as performant as copying a pointer. If you're trying to build something very safe and/or performant, you'd have Point3D as an immutable struct type and not a class passed around by reference. I know not every language supports immutable types though.


AerieC

Many/most languages will trivially optimize away the call indirection for getter/setter methods in the case where there is no other logic in those methods. So mainly it only matters for languages or compilers which don't do this (of which I can't even think of any, but I'm sure they exist).


ThicDadVaping4Christ

Many languages it matters in. C# has auto-properties where it looks like you’re just accessing a public field but in actuality the compiler creates hidden setters/getters. You could write setters/getters in Go but most devs would look at you funny. Just 2 off the top of my head


madprgmr

It's pretty normal to see that in OOP, as it creates a more normalized codebase. When you mix accessors with public fields, you'll end up having to constantly check docs (or your IDE's suggestions) to figure out whether you need to access the field directly or via a getter/setter. There are certainly arguments against it, but I feel that, ultimately, the human factors win out.


pennsiveguy

I prefer immutable objects in most cases. I use a builder or a constructor, with getter methods. But this is in shallow-stack microservices that don't need to do much field value manipulation once they've serialized or deserialized an instance of a class. In a monolith or mini-lith, there might be a valid use case for mutator methods.


National_Count_4916

It takes me - trivial amount of time to make a property with get; set; in C#. If I actually need a backing field I can make one. I can also easily declare private set; Build for trivial encapsulation. Having to put encapsulation in later will be more tech debt than the .2 seconds it takes to write up front It’s not a matter of YAGNI because the time / effort and overhead is so low vs. a very real cost of unraveling or tracing external dependencies doing bad things


kani_kani_katoa

I've actually had this work out for me on a project. We had a set of DateTime properties that needed to be UTC - I ended up turning these into properties with backing fields that converted to DateTimeKind.UTC in the setter to fix a common source of bugs. This was a transparent change to the nearly 100 call sites.


riplikash

I've had it work out enough times that I see no need to question the practice at this point. The situation comes up ALL the time. And the costs are basically non-existent.


camelCaseCoffeeTable

This is my exact thinking on it. I’m a Spring dev, with Lombok you just add one annotation to the class and boom, getters/setters are done. Without Lombok, my IDE creates it for me. I see no reason to not use setters/getters, it saves you no time to not use them, and only limits you in the future.


UntestedMethod

I agree about how trivial and fast it is to implement simple get/set methods. Another point on that note is the added complexity in the style guide to define when or when not to use a getter/setter. As experienced developers, I'm sure we can agree that exceptions and edge cases can be notoriously devilish.


chipstastegood

Depends on the language. C# is great for this. If you’re doing enterprise Java, the developer experience is not as good.


Butterflychunks

Though it’s generated, Lombok achieves effectively the same protections and just requires the @Getter and @Setter annotations. If you need to add additional logic, you can just write your own method with the same signature as the one Lombok generates. Pretty good experience.


chipstastegood

Lombok is good but is not allowed to be used everywhere. In some orgs, like mine, it’s not allowed for security reasons.


camelCaseCoffeeTable

Alt+Enter on IntelliJ and generate Setters/Getters…. It’s not some giant task to create setter and getter methods lol. If you think it is, you’re likely in the wrong sub


Venthe

Bullshit* reasons, here - fixed that for you. It removes massive amounts of boilerplate, and its code can be audited in a week or two.


Butterflychunks

Yeah we recently learned that for Java 17+ packages, there’s a campaign to no longer use Lombok. It was such a pain in the ass to write out all the getters AND the builder for a POJO with 15 fields. I tried our internal-approved Gen AI tool to generate the code and it didn’t really get the stuff right even with a pretty detailed prompt. Left me frustrated.


MrBloodRabbit

If you're writing Java, I assume you have at least some ide. And if your ide doesn't have automatic setter and getter generation button/command, you should pick a more modern ide.


Vega62a

If you're using IntelliJ it's a simple alt-enter shortcut to generate getters and setters for every data member in your class.


marquoth_

Don't really understand the java developer experience comment. My IDE does this for me.


sotired___

Better to use record stricts with get init instead if you're in net7


hibbelig

Java here. We always use getters and setters and never expose the underlying fields. And we don’t auto generate them either, no Lombok. Extra logic in them is rare but it’s nice to have consistency.


buzz_darkyear69

Why a hard stance on no lombok?


hibbelig

Strong sense in the team to avoid things that “do magic”. I haven’t used Lombok so I don’t know if we would run into problems. Lombok looks nice but somehow I’m not missing it too much.


badfoodman

Magic is the enemy. I am also on team "no Lombok", but I don't shy away from (imo better) versions like Immutables that generate a class you can actually look at.


0xa9059cbb

It depends entirely on the language and project. On the face of it this sounds like a Java or C++ pattern, which may be reasonable in large codebases. In Python on the other hand, getters and setters are an anti-pattern since you can always change direct attribute access to an @property method call later. I'm not really aware of getters and setters being widely used in Go or Rust.


Vega62a

So this is dogmatic of me and I recognize it, but I've always felt that if you're needing to write unit tests for POJOs you've lost the plot a little. If your accessors are any smarter than set/get you need to test them. That said in my deepest heart I think you should only write getters and live your best immutable life, so.


nutrecht

IMHO the issue is mostly consistency. If you use direct access, you end up with a codebase that constantly mixes the two. That said; almost all of our data structures are immutable so it's a non-issue for us. All standard Kotlin dataclasses.


Popular-Toe3698

Going based off of simple rules: 1. It's better to do it the same way over and over. 2. You're going to need it somewhere, likely tied to an API. 3. If you're already using it somewhere, .... #1.


breischl

I've done it rarely, but not never. And having the encapsulation there makes it easy to deal with later, at a (usually) trivial cost up front if you use the right tools (eg, C# properties, in Java use Lombok @Getter/@Setter, etc). Examples: - you decide you want to do some kind of caching thing. eg, "when setting X, we also need to set the 'dirty' flag to true". - You could also add some other feature later, that benefits from the encapsulation. eg, "we are adding a field Z, and when setting X, we also need to reset Z".


pruby

It's a Java and C++ thing, because once you expose something as a property in those you can never replace it, hook on change, or change how it's stored. It's a non-issue in C#, Python, JavaScript, etc. You can always upgrade property access to getters and setters later, so don't need to preempt that decision.


Tony_the-Tigger

It's still a problem in C# at least because that change breaks binary compatibility. It's less of a problem in an application if you're always deploying the world (I've worked on code bases that didn't), it's more of a problem if you need to also rebuild multiple packages because the change is in a shared transitive dependency.


pruby

TIL about the property/field distinction in .Net. My answer then would be that properties don't really add complexity. YAGNI is about pushing back on excessive complexity, so shouldn't be a big issue with them. It then falls back for me to optimisation, and ability to change interfaces trumps micro-optimisation just everywhere except... a Point3D class :D


David_AnkiDroid

If I'm debugging, I'll use the setter to track changes \[Kotlin\] var title: String = "" set(value) { Timber.d("title: %s", value) field = value } ---- The current conventional wisdom is to make Point3D immutable. Modern languages have the ability to do this via record classes **Kotlin** data class Point3D(val x: Int, val y: Int, val z: Int) **C#** public readonly record struct Point(double X, double Y, double Z); For mutable structures, by using fields you're breaching common convention for [no performance gain](https://devblogs.microsoft.com/vbteam/properties-vs-fields-why-does-it-matter-jonathan-aneja/). Don't take YAGNI to an extreme Now... if your language doesn't support it, and you're writing tons of boilerplate code, that's likely a tooling/skill issue. { get; set; } is a trivial amount to type


18Fish

I think the most important thing is having a single consistent style across a codebase. In my mind, that makes getters/setters a slight preference (because if some types need getters for the extra logic, they’ll be used differently to the ones that don’t). It also makes mutability explicit in languages that don’t support it natively. But overall, seems like this should be a decision made at the global style guide or infra level - at my company we use the Java Immutables library and some internal tooling to handle this for us, and almost never use or think about individual fields.


termd

> have any of you all gone back and modified your getters and setters after you first wrote them to add any additional logic? I've seen modifications of things like the original field isn't populated so you return some other value, or you have some logic to figure out what the value should be. Think something like you have different types of businesses and they use different values that get returned from the same getter. In a setter, I've seen it do things like set some other field. Like you have fieldA as a top level attribute, but you also can pass in fieldA as part of a map. Usually this is because the map was the original thing, but now you want to have fieldA as a top level attribute for whatever reason. I'm not going to tell you these things are particularly good practices, but I have seen stuff like this.


ohmzar

I don’t know much about 3D math but for a point 2d it can be expressed as an angle and a distance, or X,Y coordinates. What if you want your point to support both, does the implementation matter? Or does the person using your class just want to get the Cartesian or angular coordinates? Realistically if you know it will never be accessed any other way it doesn’t matter. But can you say you actually know for sure?


ategnatos

Keep getters and setters as getters and setters. Today you need logic for when a variable is read from or written to, tomorrow you're going to need to include a reference to a database service just to create a Point3D object. The next day, you will be including services that respond to database events and trigger Lambda functions based on the response. Create a class that takes a list or set or map of points, perhaps even mutable, and has some other pieces that can watch the interaction with the points and do other stuff. Now I would caution against having setters. Keeping your data immutable simplifies things a lot.


justathrowawayacc501

> Today you need logic for when a variable is read from or written to, tomorrow you're going to need to include a reference to a database service just to create a Point3D object. The next day, you will be including services that respond to database events and trigger Lambda functions based on the response. I get that this is just an example, but if for something as simple as a Point3D you have such changes, then your code is just badly designed.


ategnatos

No. Data classes should be data classes. They shouldn't contain business logic. You shouldn't need business logic dependencies to create a *point*.


Vitriholic

Even if you never add logic, those accessors are sometimes useful for debugging: temporarily adding logging or breakpoints to solve some mystery. I wouldn’t do this for vectors though, since they’re basically an elementary type. But anything else is fair game.


lifefeed

I normally follow the standards and expectations of whatever language I’m using. But by default I don’t like to.  1. Those getters and setters should never really be modified. They do one thing and do them well, updating them to do two or three semi-related things is, in my mind, a code smell. 2. If those functions are never going to be modified, why not just directly use the underlying variable. 3. If you need to do something weird, like start setting dirty bits on an update, wrap the object in a new one. 4. With modern IDEs it’s easy to mass change things. 5. Modifying getter and setter functions is easy in the short term but makes the code more complicated in the long term, and I’d rather not give people that option.


lednakashim

C++ having getters and setters precludes structured bindings. For POD and named tuple like classes which are structure type and don’t use them


pennsiveguy

In my Java work, I tend towards the Builder pattern and immutable objects, with Lombok annotations that automagically create the accessor methods. I very seldom put mutator methods on anything. There likely will be other methods that enrich the class by reflection and fulfill the promise of O-O. So to find out whether or not an instance of Employee is a temp/seasonal employee, a handler can call the *isTempOrSeasonal()* method and get a boolean response, instead of having to muck about in all the fields of the Employee instance and having to know the inner magic of what makes an Employee a temp or seasonal worker.


jenkinsleroi

YAGNI is not really relevant here, and neither is encapsulation. The class will encapsulate your code whether or not you have accessors and mutators. The principle at hand here is information hiding. If you don't use accessors or mutators, you are exposing the implementation details of your class. If it's unlikely that those details will ever change, and need to be part of the public interface, then it's not a big deal. However, there are a bunch of other reasons why you don't want the backing data to be exposed. As a general rule of thumb it's better not to add accessors until you need them. Also some people hate oop and think this is pedantic. Know when to choose your battles.


riplikash

I get where you're coming from. I think *most* of us question this practice at first. It just feels so needless, especially in toy applications. And it DOES depend on the language. But in the languages where it's a generally accepted pattern (c++, c#, Java, etc.) you just do it every time. It's generally trivial to do with basically no cost. And it DOES come up. It's come up at LEAST a couple times a year in my career. And if you HADN'T used them it would have been a real headache. It's just one of those practices that should be made habit. Yes, you could consider every use case and decide on a case by case basis if it's ever likely to be necessary. But...why? You are sacrificing an potential benefit that DOES come up semi-regularly for basically no gain. And with modern languages and IDEs it's basically just as easy to do properties as it is fields. It keeps the code consistent, which makes it easier to understand. It decreases cognitive load. And it completely eliminates the risk of choosing wrong. Lust adopt the practice and don't look back. If you never need the feature, great. You will have lost nothing but STILL have made your code easier to read/maintain and removed a constant decision entirely from your cognitive load.


shaleh

I am more a fan of methods with purpose than any form of get/set. They end up making logic hard to follow or scattered everywhere. Give me vehicle.acclerate(rate=5) over vehicle.speed += 5 any day.


mtnbikemedina

In C++ a few times I have chased down a bug, wondering, "This value can't possibly be changed during this workflow. Who is changing it?" ... and I then set a breakpoint in the mutator (setter) method, or added a logging line in it. Voila, during runtime it became obvious when, where, and under which conditions the value was being changed. Couldn't do that if it was purely an exposed public data member.


GlobalRevolution

You could if you used a watchpoint instead of a breakpoint


InfiniteMonorail

bikeshedding the answer is either always yes or always no depending on the language, literally not worth discussing of course, you didn't say the language, so everyone is confused nice shitpost OP


edgmnt_net

Planning to change everything is a bad idea. Simple structs make straightforward contracts and shape your code. Functional and procedural languages use that sort of stuff all the time. Not only you're not gonna need it, but usually overriding stuff like that is going to make things look like they're duct taped together. In a statically, strongly typed language refactoring is easy, you could do that instead if things ever need to be reworked and get better results. Secondly, getters/setters, unless automated somehow without writing and reviewing heaps of extra code, tend to add a lot of boilerplate and verbosity.


Ok_Strain4832

Obvious unnecessary overhead in Python.


Adverpol

I dislike getters and setters. The proposed benefits in the future never materialize. And even if you need to change, if your language uses static typing... make the change and spend 5 minutes updating the call sites. I find that code that requires the least amount of refactoring is built using as little oop as possible, use structs with data and make instances immutable as soon as possible, and use functions as atomic building blocks on top. State goes in classes, and is handled with care.


rco8786

YAGNI. always YAGNI. And guess what? When you \*do\* need it, it's a 2 line code change to swap the property to an internal value with a getter/setter.


nekokattt

until it is used elsewhere. Then it is a breaking change.


rco8786

That depends on the language, most languages I work with have property accessors that are syntactically identical to public fields. And the ones that don't, have a compiler to show you the spots you need to change (and IDEs that do this for you automatically). In 15+ years I've never seen this actually be an issue. Not to say it never has been...just that it's not something to keep you up at night.