Object-oriented – How exactly are getters and setters defined

encapsulationgettersobject-orientedsettersterminology

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?

Best Answer

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.