10 ms·
... To write such a class responsibly, one has to write a lot of low-value, repetitive code: constructors, accessors ... If you're writing a plain data class,
by HumanDrivenDev 9y ago
... To write such a class responsibly, one has to write a lot of low-value, repetitive code: constructors, accessors ...
If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it.
I will be forever perplexed by the idea of getters and setters (and this extends to C#s syntax sugar). I have no idea what problem they solve. If you're at the level of plain data, then just make a class with public fields and no methods. If you're trying to write a 'higher level' object - then don't refer to the names of fields in your method names. The getter/setter/property approach is just the worst of both worlds. They make explicit reference to an objects internal fields, while at the same time obfuscating what happens when you actually access them.
- iamandoni 9y agoWhile I mostly agree, getters without setters is a nice way to expose that youre data is immutable rather than relying on final fields
- opmac 9y agoJust use public final. That is the defacto way to make immutable data classes. Why would a data class need non final fields?
- arthur_pryor 9y agoi'm a little rusty on my java, but i don't think this will work for non-constants (i.e. it won't work for things you don't set at compile time). to my knowledge, there's no "make this a constant after the first time the value is set" declaration in java (or any language that i'm aware of).
- dhosek 9y agoIf you declare a field final in Java, you either need to set it at declaration or in the constructor, so it will work with things set at compile time.
- pvg 9y agoYou're cutting out/ignoring a big chunk of the quote and then arguing a point the author didn't make. Simply accessing properties directly doesn't solve the problem.
- HumanDrivenDev 9y agoYes, I am. It was a separate tangent, and a bit off-topic.
- flukus 9y agoYou'll get you run out of town with that level of heresy in most java/c# shops. Getters and Setters are great when you want finer control over what can access certain fields, in a List class for instance, I wouldn't want the length to be externally writable. But somewhere along the way it went from a useful feature in some circumstances to a mandatory feature in all circumstances. In the c# world "public int Id;" will fail code review but "public int Id { get; set; }" will be just fine. I've never seen a justification for it though, if we make a change in future it's going to take just as much work and 99.99% of the time will never be required. But we have to appease the encapsulation gods.
- hackinthebochs 9y agoI don't understand your complaint. The problem with getters and setters was the substantial tedious boilerplate required. C# completely does away with that to where there is no meaningful difference between the two in terms of typing required, while at the same time providing the benefit of encapsulation. So what's the problem? Do you really object to 14 more chars to type? That's absurd.
- flukus 9y ago> The problem with getters and setters was the substantial tedious boilerplate required The problem isn't the tedious boilerplate, it's that it isn't necessary most of the time, 99%+ of getters and setters could be replaced with public fields. c# solved a problem that only existed in the first place because of cargo cult practices. > while at the same time providing the benefit of encapsulation It potentially provides encapsulation and I don't really object to them there, but if we just used them where they were really needed then we having a setter/getter function is would have been just fine as well and the language would be simpler. > Do you really object to 14 more chars to type? That's absurd. I see you didn't use c# before version 3. Originally they required almost as much boiler plate as java, I've still got a mountain of code around here from that time and all they add to the codebase is noise.
- hackinthebochs 9y ago
- derefr 9y ago> obfuscating what happens when you actually access them This is the point, AFAICT. In languages with both primitive "read/write field" operations that can't be interceded upon, but also with interfaces/protocols, "obfuscating" (encapsulating) a field access in getter/setter methods is how you allow for alternative implementations of the interface/protocol. Specifying your object's interface in terms of getters/setters allows for objects that satisfy your interface but which might: • read from another object (flyweight pattern) • read from another object and return an altered value (decorator pattern)[1] • read from an object in a remote VM over a distribution protocol (proxy pattern) Etc. Then a client can build these things and feed them to your library, and you won't know that they're any different than your "ordinary" data objects. You don't see this in languages with "pure" message-passing OOP, like Ruby or Smalltalk, because there's no (exposed) primitive for field access. All field access—at the AST level—goes through an implicit getter/setter, and so all field access can be redefined. But in a language like Java, where field access has its own semantics divorced from function calls, you need getters/setters to achieve a similar effect. And yes, this can cause problems—e.g. making expected O(1) accesses into O(N) accesses, or causing synchronous caller methods to block/yield. This is why languages like Elixir, despite having dynamic-dispatch features, have chosen to discourage dynamic dispatch: it allows someone reading the code to be sure, from the particular function being called, what its time-and-space-complexity is. You know when you call MapSet.fetch that you're getting O(1) behaviour, and when you call Enum.fetch that you're not—rather than just accessing MapSets through the Enum API and having them "magically" be O(1) instead of O(N).) --- [1] Which is a failure of the Open-Closed Principle. That doesn't stop people.
- mikeash 9y agoI like Swift's approach to this. (I'm sure other languages do it too, that's just the one I know that does this.) If you write a property (what other languages might call a "field") then by default it's a stored property, i.e. it's backed by a bit of memory in the object. If you need to take actions on changes, you can implement a willSet or didSet handler to do so. If you need to change how the value is stored and retrieved altogether, you can change it to a computed property, which invokes code to get and set rather than reading and writing to a chunk of memory. All of this is completely transparent to the caller. It's particularly interesting because it still acts like a mutable value. You can still pass a reference to such a field into an inout parameter using &, or call mutating methods on it. Behind the scenes, the compiler does a read/modify/write dance rather than mutating the value in place.
- virmundi 9y agoIn Java, they came with the bean standard. The goal was to codify properties to make reflection easier. That’s it. If you don’t need reflection or the bean utilities that help with that, just use simple public final T values.
- mohaine 9y agoGetters/Setters do have a couple of reasons to exist: 1) Allowing you to validate data/morph data on your objects on set. (example: Date is not a workday) 2) Allow others to do either 1 or other actions on set/get (examples: Hibernate entity beans that update db/set dirty on set, GUI can extend object to update on set) That said it was a total PITA when this first became popular. I spent way too much time changing code over because that was now "best practice". And don't get me started on Boolean not being get but is or has.
- drizze 9y agoTo provide flexibility in the future. When your data comes from a method you can change its source without changing the caller. This can be very useful and should be leveraged whenever possible.
- HumanDrivenDev 9y agoBut by definition getters and setters lack lexibility. They expose the internal representation of an object. They stop really being "objects" - high level opaque things you send messages to - and they turn into big porous bags of fields. To clarify, I would not consider something like this a setter: class Monster { int health; void Damage(int d) { this.health -= d; } } True, it is a method that just sets a variable. But it makes no mention of that variable. It's defined in terms of its actual purpose (inflicting damage on a monster), not its implementation (modifying an internal field called 'health'). There is definitely a time and place for plain data objects. But if you find yourself actually needing validation and preprocessing in your get/set, then you probably have a 'real' object hiding their. Stop being lazy and give it proper methods.
- hackits 9y ago`Technically` The current representation of `objects` in java is a abomination to the original idea behind object's. Hell even the use of class, members and fields fly in the face of what real objects are.
- wvenable 9y agoDo physicists argue about the true nature of gravity because Newton had the "original idea" behind it?
- HumanDrivenDev 9y agoWhat do you mean by "real objects"? Are you refering to prototype OO?
- 9y ago
- bunderbunder 9y agoI can't speak to Java, but in C#, the original goal was to reduce coupling. You can add behavior to getter and setter methods without breaking binary compatibility among packages. It absolutely is obfuscation, to the extent that encapsulation is just a special kind of obfuscation. Possibly more importantly, public fields give you no way to create immutable types.
- flukus 9y ago> Possibly more importantly, public fields give you no way to create immutable types. public readonly int Foo; readonly fields can only be set in the constructor, great for immutable types and with much better guarantees than protected/private/no setters.
- InclinedPlane 9y agoAnd when you want to make Foo no longer a primary value and instead calculated from some other field? When you want to add logging to every change of Foo? Every access? When you want to switch to having Foo's value come from a database? Web service?
- flukus 9y agoThen I'd change it to a property and recompile. If it's value comes from the database or a web service then nothing has to change, whatever is calling the service will invoke the constructor as always. The only exception here is for public APIs, but that's a minority of projects.
- zmmmmm 9y ago> Then I'd change it to a property and recompile You mean, change it to a property, then fix dozens or hundreds of references, possibly in downstream dependencies some of which aren't under your control and can't be changed. Sounds fun.
- alkonaut 9y ago
- Tarean 9y agoIf you have a temperature class with a celsius field and change the internal representation to kelvin you have to update all client code to call a conversion method. C#s syntax sugar allows you to slot in the conversion method without a breaking change but it screws with the cost model of field accessing when used unresponsibly. Java doesn't have it so you would have to hide everything behind getters if you don't want to tie yourself to a representation. Whether a data class should touch enough code to make the transformation a burden is another matter, though.
- HumanDrivenDev 9y agoI appreciate you thinking of an example, but I guess I find it a bit convoluted. Couldn't you also refactor that by changing the constructor of your temperature class so it converts things to Kelvins, rather than converting it every time you call the getter?
- Tarean 9y agoSure, but every field access like Temperature temp = Temperature.fromCelsius(13); ... System.out.println(temp.celsius); would have to be changed to System.out.println(temp.getCelsius()); when the internal representation is changed.
- HumanDrivenDev 9y agoI get what you're saying, but at the same time I don't understand how you'd implement the class and why. class Temperature { public final double celcius, kelvins; Temperature(int celcius, int kelvins) { this.celcius = celcius; this.kelvins = kelvins; } public static Temperature fromCelcius(int c) { return new Celcius(c, c - 273.15); } } What's wrong with that approach, and how would you do it?
- goflyapig 9y agoThis only works if your class is immutable. If a client sets either of those fields, they will now be out of sync.
- geodel 9y agoGenerating getters and setters are day jobs for 'JavaBean Jerries' which comprise most if not all enterprise Java developers.
- vaskebjorn 9y agoIn my experience writing getters and setters has been boilerplate 99% of the time. But I still write them because situations arise where you do need to change the nature of that property, sometimes dynamically, and then it's suddenly worth it. You can, for instance, change a getter and none of the class's clients need to know or care about the change. Though I haven't used Groovy much I like their approach to this: "Although the compiler creates the usual getter/setter logic, if you wish to do anything additional or different in those getters/setters, you’re free to still provide them, and the compiler will use your logic, instead of the default generated one."
- chubot 9y agoWhy don't you just use plain fields, and if you need to change it later, delete the field and go fix all compile errors? That's an easy way to find all usages. Or are you not talking about a statically-typed language which would find the errors when you temporarily delete a field?
- whitenoice 9y agoYou might want to look into Project Lombok. It does exactly that, and it works well.
- digaozao 9y ago
- moron4hire 9y agoYou don't get to execute validation code on a bare field right away.
- HumanDrivenDev 9y agoWhy not give your "setters" a real name that describes what they're doing? https://news.ycombinator.com/item?id=15606777 https://news.ycombinator.com/item?id=15606777 In the structs & records world (C, F#, Rust, etc) they never seem to have this issue. Either the struct is completely transparent and you can read and write fields at will, or it's completely opaque and the functions that operate on it have better names/semantics than "setField".
- geophile 9y agoI think getters/setters are an abomination resulting from a sensible OO idea taken too far. Having private fields and public methods has benefits that are so obvious that I won't belabor the point. Sometimes -- maybe even often -- you really do want to get and set some fields, so then you have getters and setters. But applying this pattern blindly, to all fields, is insane and, as many people on this thread have noted, defeat the point of private fields and public methods. Just make the fields public, because that's how much protection you have anyway. (Adding code around the getting and setting is, of course, easier with methods already in place.) I think this trend really got started with Java Beans, in which getters/setters were required (unless you wanted to write yet more code to nominate other methods as the getters and setters). And then the stupidity set in. Well why wouldn't you want your object to be a bean? Beans are good! Be a bean. I believe that things like corporate coding standards then kicked in and made this nonsense unavoidable.
- platz 9y agojust use a struct for plain data
- jt2190 9y agoThe pattern evolved from early Java’s lack of reflection. In order to give tools the ability to set/get data, we got the JavaBean. The culture internalized the pattern, and we’ve been mindlessly doing it ever since.
- dboreham 9y agoAppreciate you posting the actual history. One thing I've noticed more and more over the years is this tendency for folks to do things that under analysis make no sense and have no benefit. Even worse, I have a bad feeling that 20 years ago I was one of those people...
- pjmlp 9y agoYou this a lot with C and C with Classes devs, micro-optimizing every single line of code as they write them, based on urban myths or past legends without touching a profiler a single time.
- cultvoid 9y agoThis is correct. JavaBeans were a bad solution to a problem. It was Swing (or was it AWT then?) that needed it first, so that tool builders could allow widgets to have their properties customised. So the vile JavaBean conventions took hold. I only quibble on the "mindlessly" part. I will never add a get/set in a class if it isn't needed. But invariably, in a Java project, some library somewhere insists that I have them. So eventually I find I've reluctantly added them. Sometimes you can get away with leaving them private, sometimes not. It's a pain in the neck and like many things in Java, it should have been sorted out years ago.
- danvasquez29 9y agoI do it in PHP to make something immutable. data goes into the constructor and then only getters are provided.
- aomix 9y agoThese kind of classes are structs with busy work attached. At work I feel a little guilty when I delete them over the course of refactoring but if no processing on the incoming and outgoing data is necessary then public fields are better in every way by being easier and simpler.
- xapata 9y agoIf you have the option of a property later, there's no reason to start with accessor methods, but some languages don't support properties.
- tobiasSoftware 9y agoGetters and setters are confusing because there are no reasons to use them for small projects, like what you would build in a college course. Software becomes exponentially confusing the larger it becomes. In addition, one piece of software may be built by multiple teams, such as using third party libraries. The best way to handle the additional complexity is to split each section into two: the interface (public) and the implementation (private). Here are the reasons why: First, change. Changes to code happen all of the time. If someone wants to build a library so that many other users can interact with it, they have to realize that one day changes to that library will need to happen. If code is separated into public and private properly, then any private functions and fields can be rewired, and as long as the rewiring makes the public functions and fields perform the same, then the change will not break anything. How important is not breaking things? Well anyone familiar with Python's 2 and 3 schism knows the pain of changes that break compatibility. Second, visibility. When you are interacting with a large codebase, you need to know what functions and fields to interact with. IDEs have very useful tools that can list these for you, but if everything is public then they will list everything. If 90% of your codebase is private data, that is a lot of useless functions and fields to sort through! Third, hackery. When you are building a large codebase, there may be some things you don't want you programmers interacting with it to do. Users might take advantage of quirks in your code that were never meant to be used that way. XKCD's Spacebar Heating comic illustrates this nicely. Another reason may be security, as you might not want someone to have full access to functions and fields to poke around and understand your code better. So these are the reasons why public and private are important concepts. The problem is then if something starts out as public, it won't have any of these advantages. If you want to change it to private later on, then you are screwed. So the Java solution is to make everything private from the beginning. Vanilla getters and setters are really just making private data appear public. Then if the data needs to be changed from "public" to private, the getters and setters can be modified accordingly. Python's property approach is a similar concept, but infinitely better, as instead of relying on a programmer to build getters and setters, the language itself invisibly builds them under the hood. Then if you want to change something from public to private, instead of being screwed, you just add a property tag with the getter and setter code to change the getter and setter from an invisible default to a visible modification.
- camus2 9y ago> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it. When doing pure OOP, objects should only communicate via methods, period, it's called state encapsulation and is one of the core principle of OOP, the second being polymorphism. > I will be forever perplexed by the idea of getters and setters (and this extends to C#s syntax sugar). I have no idea what problem they solve. Then you don't understand encapsulation.
- mustardo 9y agoFor arguments sake you could say foo.bar = "baz" syntactic suggar for setBar("baz") sure you now cant add logic to the set method without introducing a real setBar method (and therefore breaking your public interface) but for immutable final DTO / POD style classes that don't have setters just use a public final field and be done with it There's a difference between understanding encapsulation and being pragmatic
- nwatson 9y agoEven for just plain data values, getters and setters can be decorated with annotations that modify the member-"property's" behavior depending on context, e.g., what should happen to this member when I serialize to JSON ... or when I read from a DB? I've found these decorators real useful in the past ... and while they balloon the code for the "data class" itself, they eliminate a lot of code elsewhere. E.g., this may violate some "separation of concerns", but often one will want to: (a) read some hierarchical data from JSON in a web service request; (b) persist these elements to DB, maintaining proper relations between entities read in from JSON but now persisted as rows to multiple tables in a DB; (c) at some later point read back some of those elements and reconstruct the hierarchy and perhaps transform it or merge it with other hierarchies; (d) perhaps re-persist it, or send it out as a JSON response ... so ... ... in such a situation I am dealing with the same small set of "data classes" everywhere -- but when persisting or reading from a DB I have data fields that represent "primary" or "foreign key" DB values -- I possibly don't want those field values to ever get written to JSON; other member fields deal with the semantic hierarchy of that data in the JSON-like or internal-Java view (e.g., lists, maps, pointers-to-parents-in-hierarchies) ... but I don't want those members ever to be written to the DB (since they're replaced by PK/FK references) ... >>> rather than maintaining two sets of data classes for the two alternative representations (and the ugly boilerplate required to translate between them), it's much easier to have just one set of semantic data classes that each knows how to live in each context (DB, JSON, in-memory, etc. ...). <<< The key to telling these data classes and their members to behave differently, in Java, for each context (JSON deserialize vs JSON serialize vs DB read vs DB write), is to use decorators on their setters and getters. EDIT: included more lengthy rationale.
- michaelgrosner2 9y agoIn C# 6, using properties is actually slightly less verbose, "public int Foo { get; }" vs "public readonly int Foo;". Also, you can easily slap an interface around your data class if you need to later. So my thinking has switched when writing new C# -- why not use a property?
- wtetzner 9y ago> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it. I think it's because you can't specify fields interfaces. If you different data classes, but you want them all to be "Named", you need "getName()" on your "Named" interface, because you can say that it should have a "name" field. Of course, that's a language flaw, but it's one that people have to work around.
- FollowSteph3 9y agoThey are useless until one day they become extremely useful. In other words most of the time there’s minimal advantages. However by following good form you will eventually come across and instance where you have to do something and instead of having to change code in tons and tons of places, places you may not event have access to such as a public API, you don’t realize the importance. Hopefully you never across the need to do this, it’s pretty rare, but when it happens I can’t tell you how valuable it is. The benefits are all in code maintenance. Again most of the time it’s useless but when you need I can’t tell you how incredibly useful it can be. And once you come across such an instance you never again ask why or refuse to do it ;)
- FollowSteph3 9y agoLet me give a concrete example from my past. We had a public API of POJO domain objects that could be used to render templated files, think string replace. It worked great until one day someone had a special character that caused it all to fail. How do you fix this? Ask all customers to clean their values? Good luck with that!! However from our side we just added the code to clean the output, escape the special character for the templating engine, and everything worked great. The only other option was to have thousands of customers with live systems edit their templates and or data to fix that one bad character. It affected a lot of people due to another unrelated update. Anyways had we not been forcing the use of setters and getters a solution would have been on a whole other scale! And no we couldn’t edit the template engine, etc, because in most cases it was valid.
- qw 9y agoWhat use did you have from the getter? That seems like a situation where you would only change the setter (or a builder if you use that pattern).
- merb 9y agoor the constructor..
- FollowSteph3 9y ago
- ScottBurson 9y agoSetters, at least, I find to be frequently useful places to put breakpoints when debugging. This is quite a bit rarer with getters, but I guess it happens occasionally.
- aryehof 9y agoFrameworks elevated the need for getters and setters, given the need to programmatically access the internals of objects. Their overuse is also a consequence of the popularity of a programming style of code acting on data, typically within an application that has class data merely representing database entities, acted on by separate logic and constraints in an application/service layer. Behavior based object design seems to be an endangered species.
- cultvoid 9y agoExactly this. If you're working on a system with any need of serialization (eg to/from JSon), or presentation on some kind of view tier, or storage in a database, then the frameworks make get/set pairs inevitable, even if you fight tooth and nail not to have them. (Of course you could avoid the frameworks, but try telling your project managers that). Behavior based object design, as well as being an endangered species, probably never existed very much in the first place. I wonder if Java's popularity was partly due to people being able to appear to do OO whilst actually implementing "code acting on data" systems. You got the warm OO glow without the hard work of doing any behavior driven design.
- pilif 9y agoIf you ever have to change a fields meaning or add a new field and provide the old fields value for older clients, you can't just make it private and add a public setters and getters without breaking compatibility for all your users - not just binary compatibility but also source-level compatibility.
- BlackFly 9y agoShort answer: to avoid side effects from other parts of the code rippling into the data class. Some objects are inherently mutable and exposing a reference to them allows mutability. You might not have control of all the class definitions in your data domain in order to make them immutable. Instead, a getter and setter can create equal copies and return those. This is assuming you are talking about getters and setters on immutable objects. If you are talking about mutable objects, then they really need getters and setters to ensure that mutations on the object they return or receive do not affect them.
- josteink 9y ago> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it I'm not going to completely dismiss the such a practice may be plain old cargo-culting... But as devils-advocate, properties are implemented as methods/functions, and as such (under the hood) accessed through a vtable. This means they can be overridden in derived (generated) classes, which can then implement things like change-detection and other stuff which may be of use for a data-access/persistence class. And these derived classes can be returned in place, without the calling code knowing nothing about it. > They make explicit reference to an objects internal fields Not really. A property is supposed to be a public API, and definitely not "internal".
- haglin 9y agoSome reasons: - more efficient representation - thread safety - security (defensive copy) - validation - logging - debugging - backward compatibility