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,411
  • 5
  • 21
  • 38
  • 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' –  May 25 '17 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 '17 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. – Frank Hileman May 25 '17 at 18:29
  • @FrankHileman: Could you provide an example of a getter or setter in a non-object-oriented language? – Frank Puffer May 25 '17 at 18:31
  • Getters and setters can be used in non-OO languages to avoid making module-level variables global. For example, a getter in C might be float getLength() {return length;} – Jeanne Pindar May 25 '17 at 23:22
  • 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. – Frank Hileman May 26 '17 at 20:37
  • For me getter and setters are only for raw property (so no encapsulation in fact), so only (1), if there is something behind the scene, I prefer to name it otherwise. I may not always does that but it's really rare. It is because I work in Java and in Java get/set are commonly used by frameworks, doing something else behind the scene is wayy too risky. – Walfrat May 29 '17 at 15:13

4 Answers4

3

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.

Berin Loritsch
  • 45,784
  • 7
  • 87
  • 160
  • 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* –  May 25 '17 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. – Berin Loritsch May 26 '17 at 01: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!* –  May 26 '17 at 13:23
2

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.

Frank Hileman
  • 3,922
  • 16
  • 18
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
  • 33,282
  • 5
  • 57
  • 91
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,032
  • 2
  • 19
  • 19