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?

Frank Puffer
  • 6,459

7 Answers7

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

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.)

Erik Eidt
  • 34,819
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&lt;Double&gt;();
this.list.addAll(toSet);

}

CPlus
  • 1,209
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 ? &quot;&quot; : length + &quot; &quot; + measure;

}

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.

gnasher729
  • 49,096
-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

Cormac Mulhall
  • 5,176
  • 2
  • 21
  • 19