4

Note: Questions with similar title have been asked before, but please read the full text before claiming that this is a duplicate.

Since everybody in OOP uses the terms getter and setter, I would expect they have a well-defined meaning. But what I found are basically two statements that are somewhat contradictory:

(A) They provide read or write access to a specific attribute.

This is what practically all getters and setters I have seen in production code do. A getter returns the value of an attribute and a setter sets the value of one attribute.

On the other hand:

(B) They allow hiding the internal representation of data inside a class while still being able to access and modify it.

An example in Java:

private double x, y;
public double getX() { return x; }
public double getY() { return y; }

This obviously conforms with (A). Now according to (B) we could change the data representation:

private double angle, distance;
public double getX() { return distance * Math.cos(angle); }
public double getY() { return distance * Math.sin(angle); }

This no longer conforms with (A) because there are no longer attributes named X and Y and the return values are the result of a calculation. But I would still call them getters.

Some more examples:

  1. This is obviously a setter:

    private double length;
    public void setLength(double newLength) {
        length = newLength;
    }
    
  2. Most definitions allow the setter to do some checks:

    private double length;
    public void setLength(double newLength) {
        length = (newLength > 0) ? newLength : 0;
    }
    
  3. Not sure about this one. Note that there could be multiple setters for one attribute:

    private double length;
    public void setLengthInInches(double newLength) {
        length = 25.4 * newLength;
    }
    
  4. This one sets two attributes:

    private double length;
    private UnitType lengthUnit;
    public void setLengthInInches(double newLength) {
        length = newLength;
        lengthUnit = UNIT_INCH;
    }
    
  5. Similar to 4 but with two arguments:

    private double length;
    private UnitType lengthUnit;
    public void setLength(double newLength, UnitType newLengthUnit) {
        length = newLength;
        lengthUnit = newLengthUnit;
    }
    
  6. Another variation:

    private double length;
    private UnitType lengthUnit;
    public void setLength(LengthType newLength) {
        length = newLength.getValue();
        lengthUnit = newLength.getUnit();
    }
    
  7. Here the attribute does not exist but can be calculated:

    private double start;
    private double end;
    public void setLength(double newLength) {
        end = start + newLength;
    }
    
  8. What about this one:

    private int productId;
    private Price price;
    public void setLength(double newLength) {
        productId = getProductIdByLength(newLength);
        price = BASE_PRICE + PRICE_PER_LENGTH_UNIT * newLength;
    }
    
  9. And this one:

    private double length;
    public void setLength(SomeInput input) {
        length = input.doSomeComplicatedStuffToCalculateLength();
    }
    

Which of these are setters and which are not?

7
  • 2
    they are all getters and setters. It helps if you think of description a as being "They provide read or write access to a specific value." rather than 'attribute'
    – user232573
    May 25, 2017 at 12:34
  • 2
    I would say that getters and setters by the A definition are not part of OOP/OOD. The B definition is better aligned with OO concepts. That's fundamentally what (g/s)etters are: a mixture of procedural and OO approaches.
    – JimmyJames
    May 25, 2017 at 16:14
  • 1
    Getters and Setters probably are as old as Smalltalk, but the terminology is newer. They have nothing specifically to do with OOP or OOD. May 25, 2017 at 18:29
  • @FrankHileman: Could you provide an example of a getter or setter in a non-object-oriented language? May 25, 2017 at 18:31
  • 1
    @FrankPuffer They are simply functions that retrieve a value, given a data structure, or set a value. There's quite a few ways to use encapsulation in non OO languages, typically by using an opaque data type externally. May 26, 2017 at 20:37

7 Answers 7

4

I like the C#/Ruby/Python/etc. terminology of Properties. I think this helps disambiguate the concept a bit. In C# properties are a nice way to write formalized setters and getters. In Java properties are a matter of convention (i.e. JavaBeans with the set/get pair sharing the same name).

Properties are exposed logical values that you intend for other code to interact with. As many of your examples demonstrated, internal representation is not required to match the logical representation.

As a general rule, you will find that keeping the implementation of the properties as simple as possible will give you the best option to maintain your software. Things that are perfectly acceptable in setters/getters:

  • Simple representation of internal state (i.e. exposing a class field)
  • Constraining values (setter forces value within a range)
  • Simple conversions to/from internal units (i.e. get/set XInYards can convert internal representation in meters to yards)
  • Calculated read only properties

The stuff that can get you in trouble include:

  • Mutating multiple properties when you set one
  • Performing actions that require try/catch semantics in a getter

The assumption with properties is that setting and getting values is very simple, very fast, and safe. In multiple languages, you can bind UI elements directly to your properties (even JavaBeans). If your logic is sufficiently complex enough, it would be better to provide a proper method to assign or retrieve information.

3
  • You can definitely get in trouble with what I call "Irish Setters" - they use other set Properties internally. (But the code is so friendly!) It leads to – Stack Overflow Exception - System Halted
    – user251748
    May 25, 2017 at 17:22
  • Not sure I follow what you mean. Chaining setters can be a bad idea, but do not always cause a stack overflow exception. May 26, 2017 at 1:40
  • Well, I am just a master at tying my shoelaces to a bus, I guess! What happened was that each of the setters invoked an internal method, which happened to call more than one other setter. I was doing an example to teach in class of representing money, and I had a method that would reduce any amount of coins of different denominations to the 'canonical' form. "Penny for a gumball Mickey? Thanks for the " - Doh!
    – user251748
    May 26, 2017 at 13:23
3

The most primitive definition is that the getter is a method that retrieves a value, and a setter is a method that modifies a value. There is no requirement that the value be backed by a field or even stored in the implementing object.

For .net specifically, there are a set of guidelines to follow that ensure properties (getters and setters in .net) behave predictably: Property Design

One of the most important concepts is that properties should be orthogonal; setting one property should not affect another.

1

Let's consider the motivation of being able to evolve your code base that is behind the use (and popular promotion) of getters and setters.

Giving access directly to fields restricts our capabilities to evolve our classes, for example, being able to notice when something changes.

Enter getters and setters, which can be as simple as field access or as complex as we like. Once the client is using methods instead of direct field access, we can evolve the code behind the getters & setters at will. We might even engage the use of virtual methods and overrides, and the callers will still not have to change.

Given that the purpose of getters and setters is to provide an evolutionary path for maintenance of the code, broadly speaking, we should expect to find getters and setters that have a wide range of implementations -- some that have taken advantage of this evolutionary capability (if we didn't we might as well just use direct field access).

Fundamentally, the unstated contract of getters and setters is that the value returned by the getter doesn't change until the setter is used, and that once the setter is used, the getter returns the updated value. This could be formalized (e.g. the contract/behaviors of Lenses in functional programming) but I am not aware that this has been done in OOP.

We can also add to that what @FrankHileman says that setting one property should not affect another.

Still, there are some combinations, for example, where you might consider overloaded getters & setters: a setter for setting temp in degrees F plus one for setting temp in degrees C, these we would expect both getters to return a different value if either setter is used.

In light of this, I would presume all your examples to valid getters/setters, though this requires imagining a corresponding getter, since most of your examples don't show the getter.

(And yet, yes, there are valid reasons to have a getter without setter and vice versa.)

0

Just to point out, there isn't one solution for all scenarios, getters and setters are defined per need basis to access object's attributes following OOP principles. Combining these principles could end up with various valid arguments supporting the definition of them. Here is an edge case for defining a getter following SRP and DRY principles: in MVC pattern the view components could be backed by beans encapsulating information to be displayed, those beans could include a type of getter referred by synthetic getter string of words that returns a combination of properties it encapsulates or combination of properties of other beans it encapsulates.

Example:

private Double length;
private String measure;

public String getLengthString() {
    
    return length == null ? "" : length + " " + measure;
}
0

Next sentence might be perceived being rough. Getter and setter are not for hiding internal representation, neither they are for validation / computing internal values. There are multiple arguments supporting previous sentence, the most straight forward I can think of is single responsibility principle from SOLID principles. Example 6 is a proper illustration:

private double length;
private UnitType lengthUnit;
public void setLength(LengthType newLength) {
    length = newLength.getValue();
    lengthUnit = newLength.getUnit();
}

Would the length be exposed to the outside by a getter? What is the utility of length without lengthUnit?

Here is a plainer example:

private double property;

public void setProperty(long toSet) { property = toSet; }

public long getProperty() { return (long) property; }

What is the purpose of internally representing property through double type when everything that can be done with the property the outer ecosystem knows it is of type long? None.

How are getter and setters defined? They are defined to isolate the internal representation from the externals. When the value exposed is immutable there is no need for getters and setters. When the value exposed is mutable the setter should duplicate the received reference and store it internally while the getter should return a duplicate of the internal representation since the internally stored representation should change just by calling the setter.

Here are couple of examples specific for Java programming language: Immutable value represented by a field (a value without getter and setter):

public double length = ...;

Mutable value represented by a property (a value with getter and setter):

private Date onceUponTheTime;

public Date getOnceUponTheTime() {
    
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(this.onceUponTheTime);

    return calendar.getTime();
}

public Date setOnceUponTheTime(Date toSet) {

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(toSet);

    this.onceUponTheTime = calendar.getTime();
}

... or ...

private List<Double> list;

public List<Double> getList() {
    
    return Collections.unmodifiableList(this.list);
}

public void setList(List<Double> toSet) {

    this.list = new ArrayList<Double>();
    this.list.addAll(toSet);
}
0

C++: You have a getter and setter function. You know they are functions. In the simplest case they are just inlined functions that return the value of a private member of your instance or set it to a new value.

In C++ they are implemented as ordinary member functions that can do whatever they like. Or they can be read-only if you just provide the getter. Or you can make the setter private. And the developer has to create the private members that are accessed.

Setter/getter may insulate you from changes in the class. Say you stored a distance in km and want to have setters. So you just write

double getDistanceInMiles() {
    return getDistanceInKm() / 1609.344;
}

and then you use either setter or getter. Now you have one property or attribute or whatever you call it, and two getters.

Then you have Swift with properties. You define properties. The compiler creates getter and setter for you. You can explicitly add code for the getter and setter, or the compiler creates an invisible member for you and getter/setter.

A property is used like a member variable in C++. For example x.count += 1 calls the getter to read count, adds 1, calls the setter to change the value. You can set a “will set” and “did set” method which will be executed just before or just after the setter is called. And you can create a template for a setter/getter if you have many getters and setters following the same pattern.

-1

(A) They provide read or write access to a specific attribute.

(B) They allow hiding the internal representation of data inside a class while still being able to access and modify it.

Because you access the attribute via a method they technically do both. If you changed the internal representation of the attribute this change can be hidden to code that called getter method because you have a method to transform the data to the expected format.

For example (excuse the pseudocode) say you originally store a value as and integer

class MySillyClass {
  Integer my_number = 39

  Integer myNumber() {
    return my_number
  }
}

but then you decide you want to store it as a string. Can change the string back to an integer in the getter method so that code relying on this value being an integer won't break

class MySillyClass {
  String my_number = "39"

  Integer myNumber() {
    return my_number.to_integer
  }
}

It should be pointed out that Getters and Setters are still a very bad idea and miss the fundamental point of object orientated design. Your objects should expose specific behaviour related to what they do in the system. A getter or setter is a code smell that your object is holding someone else's data and that the object is not designed correctly

7
  • 1
    -1 for the last part. It's a blanket statement that is seriously flawed. Who would store the element count of a list if not the list itself?
    – Ccm
    Sep 22, 2023 at 5:57
  • -1 for same reason.
    – gnasher729
    Nov 27, 2023 at 17:09
  • @Ccm @gnasher729 I think you are both misunderstanding what a "getter" is. A .count() method on a list is not a getter. A getter in that context would be a method that gives you access to the internal representation of the list, which you then pull out of the List object and count some where else. That would obviously be a massive code smell as you point out, the List should be counting itself. This is why getters and setters are code smells, they are devoid of behavior of the object. Nov 29, 2023 at 12:52
  • @CormacMulhall This is precisely why a blanket statement is flawed. A count method can still give you access to the internal representation of the list: it can simply return an int representing the number of values in the list. Is that a getter? or a method? btw, getters and setters (or lack of any of them) do define behavior only through their presence. If you have a setter, it means the object is capable of handling a change in whatever that setter represents. Overuse of getters and setters may signal a code smell, but then again, overuse of any pattern is a problem.
    – Ccm
    Nov 29, 2023 at 13:38
  • @Ccm "Is that a getter?" - No. If it is encapsulating behaviour of the object it is not a getter. When you call .count() on a List object you know what behaviour you are expecting the object to carry out (count the list it owns). In fact this is precisely why a getter is a code smell, theList should be responsible for counting itself. If you are pulling out data with a generic getter method and counting some where else that is a code smell because that somewhere else either should be the List or the data the object has should be over there. getters separate behaviour and data Nov 29, 2023 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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