The problem is when those getters and setters have other effects (maybe invalidating a cache?). In Java, it's considered best to just go ahead and add the getters and setters first, so that when you need to add these side effects later you don't have to modify lots of code using your library (if that is even possible). Languages like Python make this unnecessary since they have first class properties:
# Old
class Foo(object):
def __init__(self):
self.x = 0
foo = Foo()
foo.x = 1
# New
class Foo(object):
def __init__(self):
self.__x = 0
@property
def x(self):
return self.__x
@x.setter
def x(self, val):
self.__x = val
do_other_stuff()
"In Java, it's considered best to just go ahead and add the getters and setters first"
I don't think this is true. I'll concede that it may be a requirement for certain things like an ORM API, but in the general case, it's bad practice. The mere act of adding a getter violates immutability.
> The mere act of adding a getter violates immutability.
Uh what? No it does not. Writing stupid getters (or classes) might, but writing getters does not "violate immutability".
Naturally, getters are not of much use if all your fields are final and hold immutable objects, but the latter can be tricky in many OO languages.
Getters significantly improve the situation there, by providing a point at which you can clone your internal state and return a copy, letting you keep your object immutable even if you have mutable fields (of course this assumes you can deeply copy all your mutable member objects)
On the other hand, you could have "setters" using the same naming convention which do a clone-and-replace (and return the new object), that would not violate immutability (and would be easier than building objects from scratch every time from the outside) e.g.
Type setFoo(FooType foo) {
return new Type(
this.field0,
this.field1,
this.field2,
foo, // bam
this.field4);
}
many functional languages have that behavior when manipulating "records".
All of your objects are immutable? Besides that's hardly an argument for having public members, being able to remove the setter or getter (or conditionally throw exceptions in them) is one of the exact reasons why you write them.
The intent of the comment you are replying to "best practice is if you would add a public member, instead add a private member and a setter & getter" which is generally correct.