1

So I understand that if we want to change the implementation detail of a class, using those details outside of the class will cause errors when things are changed, this is why we set those fields to private. However, if we use get set methods with a private field doesn't this do the same thing? If I decided I didn't want my class to have a name and a username, just a name, and I delete the private username field, the get / set methods will break with that and it will cause the places where those methods are used to also break. Isn't referencing one class a dependency no matter what in case we change that classes methods or fields? What is the point of Get Set methods then and how do they stop code from breaking like this?

  • Get and set methods are tools to expose some attributes(values) of the object to it's consumer. If you want keep attributes private - don't use get or set methods. – Fabio Apr 07 '21 at 04:57
  • 1
    Explanation here: https://devblogs.microsoft.com/vbteam/properties-vs-fields-why-does-it-matter-jonathan-aneja/ – Ian Mercer Apr 07 '21 at 05:04
  • @IanMercer - That document seems to be not applicable to this question. Related, but not what the OP is asking. – Enigmativity Apr 07 '21 at 05:15
  • If you decide that you don't need private backing field for "username" you just remove that field. It is unclear why you believe publicly exposed property magically disappears at the same time... Obviously if you decide to remove the property you going to break compatibility but that is not what the question seem to be talking about. Please [edit] the post to clarify what exactly the example in the post should say... – Alexei Levenkov Apr 07 '21 at 05:30
  • related: https://stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors – jaco0646 Apr 07 '21 at 13:55

1 Answers1

2

However, if we use get set methods with a private field doesn't this do the same thing?

Yes. Arguably, yes. The original idea of Object Oriented Programming, as Alan Kay -who coined the term- initially thought about it, has been distorted. Alan Kay has expressed his dislike for setters:

Lots of so called object oriented languages have setters and when you have a setter on an object you turned it back into a data structure.

-- Alan Kay - Programming and Scaling (video).


Isn't referencing one class a dependency no matter what in case we change that classes methods or fields?

Correct. If you are referencing a class from another, your classes are tightly coupled. In that case a change of one class will propagate to the other. Regardless if the change is in public fields, getter, setters or something else.

If you are using an interface or similar indirection, they are loosely coupled. This looseness gives you an opportunity to stop the propagation of the change. Which you may or may not do.

Finally, if you are using an observer pattern or similar (e.g. events or listeners), you can have classes decoupled. This is, in a way, retrofitting the idea of passing messages as originally conceived by Alan Kay.


What is the point of Get Set methods then and how do they stop code from breaking like this?

They allow you to change the internal representation of the class. While the common approach is to have setters and getters correspond to a field, that does not have to be the case. A getter might return a constant, or compute a value form multiple fields. Similarly, a setter might update multiple fields (or even do nothing).

Reasons to have setters:

  • They give you an opportunity to implement validations.
  • They give you an opportunity to raise "changed" events.
  • They might be necessary to work with other systems (e.g. some Dependency Injection frameworks, also some User Interface frameworks).
  • You need to update multiple fields to keep an invariant. Presumably updating those other fields don't result in some public property changing value in an unexpected way (also don't break single responsibility principle, but that should be obvious). See Principle of least astonishment.

Reasons of getters:

  • They give you an opportunity to implement lazy initialization.
  • They give you an opportunity to return computed values.
  • They might make debugging easier. Consider some getters for DEBUG builds only.

If you had public fields, and then you decided you needed anything like what I described above, you may want to change to getters and setters. Plus, that change require to recompile the code that uses it (even if the source is the same, which would be the case with C# properties). Which is a reason it is advised to do it preemptively, in particular in code libraries (so that an application that uses it does not have to be recompiled if the library changed to a newer version that needed these changes).


These are reasons to not have getters: Often, getters exist to access a member to call method on it, which leads to very awkward interfaces (see Law of Demeter). Or to take a decision, which may lead to a Time-of-check to time-of-use bug, which also means the interface is not thread-safe ready. Or to do a computation, which is often better if the class has a method to do it itself (Tell, Don't Ask).

And for setters, aside for being a code smell of bad encapsulation, could be indicative of an unintended state machine. If code needs to call a setter (change the state), to make sure it has the intended value before calling a method, just make it a parameter (yes, even if you are going to repeat that parameter in a lot of methods). Such interface is easy to misuse, plus is not thread-safe ready. In general, avoid any interface design in which the code using it has to call things in an order that it does not forces you to (a good design will not let you call things in an order that results in an invalid state (see poka-yoke). Of course, not every contract can be expressed in the interface, we have exceptions for the rest.).

A thread-safe ready interface, is one that can be implemented in a thread-safe fashion. If an interface is not thread-safe ready, the only way to avoid threading problems while using it is to wrap access to it with locks external to it, regardless of how the interface is implemented. Often because the interface prevents consolidating reads and writes leading to a Time-of-check to time-of-use bug or an ABA problem.


There is value in public fields, when appropriate, too. In particular for performance, and for interoperability with native code. You will find, for example, that Vector types used in game development libraries often have public fields for its coordinates.


As you can see, there can be good reasons for both having and not having getters and setters. Similarly, there can be good reasons for both having or not having public fields. Plus, either case can be problematic if not used appropriately.

We have guidelines and "best practices" to avoid the pitfalls. Not having public fields is a very good default. And not every field needs getters and setters. However, you can make getters and setters, and you can make fields public. Do that if you have a good reason to do it.

If you make every field public you will likely run into trouble, braking encapsulation. If you make getters and setters for each and every field, it is not much better. Use them thoughtfully.

Theraot
  • 31,890
  • 5
  • 57
  • 86
  • Very comprehensive answer. One point I would add is that the getter/setter idiom only exists in languages whose syntax violates the [Uniform Access Principle](https://martinfowler.com/bliki/UniformAccessPrinciple.html), that is, in languages with separate syntax for fields versus functions. Unfortunately, this violation includes the most popular OO languages. – jaco0646 Apr 07 '21 at 14:09