45

I got into an interesting internet argument about getter and setter methods and encapsulation. Someone said that all they should do is an assignment (setters) or a variable access (getters) to keep them "pure" and ensure encapsulation.

  • Am I right that this would completely defeat the purpose of having getters and setters in the first place and validation and other logic (without strange side-effects of course) should be allowed?
  • When should validation happen?
    • When setting the value, inside the setter (to protect the object from ever entering an invalid state - my opinion)
    • Before setting the value, outside the setter
    • Inside the object, before each time the value is used
  • Is a setter allowed to change the value (maybe convert a valid value to some canonical internal representation)?
6
  • 20
    The best thing about getters and setters is the ability not to have them, i.e. leave of the setter and you have a read-only property, leave of the getter and you have config option whose current value is nobody's business. Nov 25, 2012 at 21:23
  • 8
    @MichaelBorgwardt Leave both out to have a clean “tell, don’t ask” interface. Properties = potential code smell. Nov 26, 2012 at 9:06
  • Obligatory link: javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
    – user281377
    Nov 26, 2012 at 9:24
  • 2
    Setters can also be used for raising an Event. Nov 26, 2012 at 9:42
  • @KonradRudolph I agree with your statement, though I'd like to really emphasize the word "potential."
    – Phil
    Nov 26, 2012 at 21:36

8 Answers 8

38

I remember having a similar argument with my lecturer when learning C++ at university. I just couldn't see the point of using getters and setters when I could make a variable public. I understand better now with years of experience and I've learned a better reason than simply saying "to maintain encapsulation".

By defining the getters and setters, you will provide a consistent interface so that if you should wish to change your implementation, you're less likely to break dependent code. This is especially important when you classes are exposed via an API and used in other apps or by 3rd parties. So what about the stuff that goes into the getter or setter?

Getters are generally better off implemented as a simple dumbed-down passthrough for access to a value because this makes their behaviour predictable. I say generally, because I've seen cases where getters have been used to access values manipulated by calculation or even by conditional code. Generally not so good if you are creating visual components for use at design time, but seemingly handy at run time. There's no real difference however between this and using a simple method, except that when you use a method, you are generally more likely to name a method more appropriately so that the functionality of the "getter" is more apparent when reading the code.

Compare the following:

int aValue = MyClass.Value;

and

int aValue = MyClass.CalculateValue();

The second option makes it clear that the value is being calculated, whereas the first example tells you that you are simply returning a value without knowing anything about the value itself.

You could perhaps argue that the following would be clearer:

int aValue = MyClass.CalculatedValue;

The problem however is that you are assuming that the value has already been manipulated elsewhere. So in the case of a getter, while you may wish to assume that something else might be going on when you are returning a value, it is difficult to make such things clear in the context of a property, and property names should never contain verbs otherwise it makes it difficult to understand at a glance whether the name used should be decorated with parentheses when accessed.

Setters are a slightly different case however. It is entirely appropriate that a setter provide some additional processing in order to validate the data being submitted to a property, throwing an exception if setting a value would violate the defined boundaries of the property. The problem that some developers have with adding processing to setters however is that there is always a temptation to have the setter do a little more, such as perform a calculation or a manipulation of the data in some manner. This is where you can get side-effects that can in some cases be either unpredictable or undesirable.

In the case of setters I'm always apply a simple rule of thumb, which is to do as little as possible to the data. For example, I will usually allow either boundary testing, and rounding so that I can both raise exceptions if appropriate, or avoid unnecessary exceptions where they can be sensibly avoided. Floating point properties are a good example where you might wish to round excessive decimal places to avoid raising an exception, while still allowing in range values to be entered with a few additional decimal places.

If you apply some sort of manipulation of the setter input, you have the same problem as with the getter, that it is difficult to allow others to know what the setter is doing by simply naming it. For example:

MyClass.Value = 12345;

Does this tell you anything about what is going to happen to the value when it is given to the setter?

How about:

MyClass.RoundValueToNearestThousand(12345);

The second example tells you exactly what is going to happen to your data, while the first won't let you know if you value is going to be arbitrarily modified. When reading code, the second example will be much clearer in it's purpose and function.

Am I right that this would completely defeat the purpose of having getters and setters in the first place and validation and other logic (without strange side-effects of course) should be allowed?

Having getters and setters isn't about encapsulation for the sake of "purity", but about encapsulating in order to allow code to be easily refactored without risking a change to the class's interface which would otherwise break the class's compatibility with calling code. Validation is entirely appropriate in a setter, however there is a small risk is that a change to the validation could break compatibility with calling code if the calling code relies on the validation occurring in a particular way. This is a generally rare and relatively low-risk situation, but it should be noted for the sake of completeness.

When should validation happen?

Validation should happen within the context of the setter prior to actually setting the value. This ensures that if an exception is thrown, the state of your object won't change and potentially invalidate its data. I generally find it better to delegate validation to a separate method which would be the first thing called within the setter, in order to keep the setter code relatively uncluttered.

Is a setter allowed to change the value (maybe convert a valid value to some canonical internal representation)?

In very rare cases, maybe. In general, it is probably better not to. This is the sort of thing best left to another method.

10
  • re: change the value, it might be reasonable to set it to -1 or some NULL flag token if the setter is passed an illegal value Nov 25, 2012 at 21:30
  • 1
    There are a couple of problems with this. Arbitrarily setting a value creates a deliberate and unclear side-effect. Also, it doesn't allow the calling code to receive feedback which could be used to better deal with illegal data. This is particularly important with values at the UI level. To be fair though, one exception I just thought of could be if allowing multiple date formats as an input, while storing the date in a standard date/time format. One could at a stretch argue that this particular "side effect" is a normalization of the data at validation, provided the input data is legal.
    – S.Robins
    Nov 25, 2012 at 21:51
  • Yes, one of the justifications of a setter is that it should return true/false if the value could be set. Nov 25, 2012 at 21:53
  • 1
    "Floating point properties are a good example where you might wish to round excessive decimal places to avoid raising an exception" In what circumstance does having too many decimal places raise an exception?
    – Mark Byers
    Nov 26, 2012 at 9:30
  • 2
    I see changing the value to a canonical representation as a form of validation. Defaulting missing values (e.g., the current date if a timestamp contains only the time) or scaling a value (.93275 -> 93.28%) to ensure internal consistency should be OK, but any such manipulations should be explicitly called out in the API documentation, especially if they are an uncommon idiom within the API.
    – TMN
    Nov 26, 2012 at 16:53
21

If the getter/setter simply mirrors the value then there is no point in having them, or in making the value private. There is nothing wrong with making some member variables public if you have a good reason. If you are writing a 3d point class then having .x, .y ,.z public makes perfect sense.

As Ralph Waldo Emerson said, "A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and the designers of Java."

Getters/setters are useful where there may be side effects, where you need to update other internal variables, recalculate cached values and protect the class from invalid inputs.

The usual justification for them, that they hide the internal structure, is generally the least useful. eg. I have these points stored as 3 floats, I might decide to store them as strings in a remote database so I'll make getters/setters to hide them, as if you could do that without having any other effect on the caller's code.

9
  • 1
    Wow, the designers of Java are divine? </jk>
    – user7043
    Nov 25, 2012 at 20:01
  • @delnan - obviously not - or they would rhyme better ;-) Nov 25, 2012 at 20:03
  • Would it be valid to create a 3d point in which x,y,z are all Float.NAN? Nov 25, 2012 at 23:58
  • 4
    I disagree with your point that "the usual justification" (hiding internal structure) is the least useful property of getters and setters. In C#, it's definitely useful to make the property an interface whose underlying structure can be changed - for example, if you only want a property available for enumeration, it's much better to say IEnumerable<T> than forcing it to something like List<T>. Your example of database access I would say is violating single responsibility - mixing the representation of the model with how it is persisted. Nov 26, 2012 at 0:04
  • @AndrewFinnell - it might be a good way of flagging points as impossible/not valid/deleted etc Nov 26, 2012 at 0:33
9

Meyer's Uniform Access Principle: "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation." is the main reason behind the getters/setters, aka Properties.

If you decide to cache or lazily compute one field of a class then you can change this anytime if you have only exposed property accessors and not the concrete data.

Value objects, simple structures don't need this abstraction but a fully fledged class does, in my opinion.

2

A common strategy for designing classes, which was introduced through the Eiffel language, is Command-Query Separation. The idea is that a method should either tell you something about the object or tell the object to do something, but not to do both.

This only relates to the public interface of the class, not the internal representation. Consider a data model object that's backed by a row in the database. You could create the object without loading the data in, then the first time you call a getter it actually does the SELECT. That's fine, you might be changing some internal details about how the object's represented but you're not changing how it appears to clients of that object. You should be able to call getters multiple times and still get the same results, even if they do different work to return those results.

Similarly a setter looks, contractually, like it just changes the state of an object. It might do that in some convoluted fashion—writing an UPDATE to a database, or passing the parameter on to some internal object. That's fine, but doing something unrelated to setting the state would be surprising.

Meyer (the creator of Eiffel) also had things to say about validation. Essentially, whenever an object is quiescent it should be in a valid state. So just after the constructor has finished, before and after (but not necessarily during) every external method call, the object's state should be consistent.

It's interesting to note that in that language, the syntax for calling a procedure and for reading an exposed attribute both look the same. In other words, a caller can't tell whether they're using some method or working directly with an instance variable. It's only in languages that don't hide this implementation detail where the question even arises—if callers couldn't tell, you could switch between a public ivar and accessors without leaking that change into client code.

1

Another acceptable thing to do is cloning. In some cases, you need to make sure, that after someone gives your class eg. a list of something, he cannot change it inside your class (nor change the object in that list). Therefore you make deep copy of parameter in setter and return deep copy in getter. (Using immutable types as parameters is annother option, but above is assuming it is not possible) But don't clone in accessors if it is not needed. Its easy to think (but not appropriately) about properies/getters and setters as constant cost operations, so this is performance landmine waiting for user of api.

1

There's not always a 1-1 mapping between property accessors and the ivars that store the data.

For example, a view class might provide a center property even though there's no ivar that stores the center of the view; setting center causes changes to other ivars, like origin or transform or whatever, but clients of the class don't know or care how center is stored provided that it works correctly. What should not happen, though, is that setting center causes things to happen beyond whatever is necessary to save the new value, however that's done.

0

The best part about setters and getters is that they make it easy to alter the rules of an API without changing the API. If you detect a bug, it's much more likely that you can fix the bug in the library and not have every consumer update its code base.

-4

I tend to believe that setters and getters are evil and should only be used in classes that are managed by a framework/container. A proper class design should not yield getters and setters.

Edit: a well-written article on this subject.

Edit2: public fields are a nonsense in an OOP approach; by saying that getters and setters are evil I do not mean that they should be replaced by public fields.

5
  • 1
    I think you're missing the point of the article, which suggests using getters/setters sparingly and to avoid exposing class data unless necessary. This IMHO is a sensible design principle which should be applied deliberately by the developer. In terms of creating properties on a class, you could simply expose a variable, but this makes it harder to provide validation when the variable is set, or to draw the value from an alternate source when "got", essentially violating encapsulation, and potentially locking you into a difficult to maintain interface design.
    – S.Robins
    Nov 27, 2012 at 10:36
  • @S.Robins In my opinion public getters and setters are wrong; public fields are more wrong (if that is comparable).
    – Random42
    Nov 27, 2012 at 10:40
  • @methodman Yes, I agree that a public field is wrong, however a public property can be useful. That property can be used to provide a place for validation or events related to the setting or returning of the data, depending on the specific requirement at the time. Getters and setters themselves aren't wrong per-se. How and when they are used or abused on the other hand can be seen as poor in terms of design and maintainability depending on the circumstances. :)
    – S.Robins
    Nov 27, 2012 at 10:46
  • @S.Robins Think about the basics of OOP and modeling; objects are supposed to copy real-life entities. Are there real-life entities that have this types of operations/properties such as getters/setters?
    – Random42
    Nov 27, 2012 at 11:20
  • To avoid having too many comments here, I'll take this conversation into this chat and address your comment there.
    – S.Robins
    Nov 27, 2012 at 11:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.