27

I have a class with a variable that is private and the class has a getter and a setter for that variable. Why not make that variable public?

The only case I think you have to use getters and setters is if you need to do some operation besides the set or the get. Example:

void my_class::set_variable(int x){
   /* Some operation like updating a log */
   this->variable = x;
}
doubleYou
  • 2,867
  • 1
  • 13
  • 26
Oni
  • 957

7 Answers7

31

This is not the most popular opinion but I don't see much of a difference.

Setters and getters are a fairly bad idea. I've thought about it and honestly I can't come up with a difference between a setter/getter a property and a public variable in practice.

In THEORY a setter and getter or property add a place to take some extra actions when a variable is set/gotten and in theory they isolate your code from changes.

In reality I rarely see setters and getters used to add an action, and when you do want to add an action you want to add it to ALL the setters or getters of a class (like logging) which should make you think that there ought to be a better solution.

As for isolating design decisions, if you change an int to a long you still have to change your setters and at least check every line that accesses them by hand--not much isolation there.

Mutable classes should be avoided by default anyway, so adding a setter should be a last resort. This is mitigated with the builder pattern where a value can be set until the object is in a desired state then the class can become immutable and your setters will throw exceptions.

As for getters--I still can't come up with much of a difference between a getter and a public final variable. The problem here is that it's bad OO in either case. You shouldn't be asking for a value from an object and operating on it — you should be asking an object to do an operation for you.

By the way, I'm in no way advocating public variables--I'm saying setters and getters (and even properties) are way too close to already being public variables.

The big problem is simply that people who aren't OO programmers are too tempted to use setters and getters to make objects into property-balls (structures) that are passed around and operated on, pretty much the opposite of how Object Oriented code works.

Bill K
  • 2,749
22

Have you ever heard about a property?

A property is a field that has "built-in" accessors (getters and setters). Java, for instance, doesn't have properties, but it's recommended to write the getters and setters to a private field. C# has properties.

So, why do we need getters and setters? Basically we need it to protect/shield the field. For instance, you're not accessing the field in memory reference, you're accessing a method that will then change the field (reference). That method is able to perform some operations that a user is not willing to know (encapsulating behavior), like in your example. Imagine, for instance, that a dozen classes use your public field and you need to change the way it's used... You would have to look at each of those classes in order to change the way they are using the field... Not so "OOlysh".

But, for instance, If you have a boolean field called dead. You should think twice before declaring a setDead and isDead. You should write accessors that are human readable, for instance, kill() instead of setDead.

However, there are a lot of frameworks that assume that you are following the JavaBean naming convention (talking about Java here), therefore, in those cases, you should declare all the getters and setters following the naming convetion.

Robert Harvey
  • 200,592
wleao
  • 1,412
8

The user of getters and setters goes into the principle of encapsulation. This will allow you to change how things work inside of the class and keeping everything functioning.

For instance if 3 other objects call foo.bar to get the value of bar and you decide to change the name of bar to far you have a problem on your hands. If the objects called foo.bar you would have to change all the classes that have this. If a setter/getter is used then you have nothing to change. Another possibility is changing the type of the variable in which case just add some transformation code to the getter/setter and you are fine.

5

Using getters and setters also enables you to control what content gets stored in a particular variable. If the content needs to be of a certain type or value, part of your setter code can be to ensure that the new value meets these requirements. If the variable is public you can't ensure these requirements are met.

This approach also makes your code more adaptable and manageable. Its much easier to make changes to the architecture of a class if you have functions in place that keep that architecture hidden from all other classes or functions that utilize that class. The already mentioned change of a variable name is only one of many many changes that are much easier to make if you have functions like getters and setters. The overall idea is to keep as much private as possible, especially your class variables.

Kenneth
  • 2,701
2

You say "The only case I think you have to use getters and setters is if you need to do some operation besides the set or the get. ".

You should use getters and setters if at some point in the future you might need to do some operation besides the set and get and you don't want to change thousands of lines of source code when that happens.

You should use getters and setters if you don't want someone to take the address of the variable and pass it around, with disastrous consequences if that variable can then be changed without any source code mentioning it, or even after the object stopped existing anymore.

gnasher729
  • 49,096
1

First off lets be clear on the paradigm.

  • Data Structures -> a layout of memory that can be traversed and manipulated by suitably knowledgeable functions.
  • Objects -> a self contained module that hides its implementation and provides an interface that may be communicated through.

Where is a getter/setter useful?

Are getters/Setters useful in Data Structures? No.

A Data Structure is a memory layout specification that is common to and manipulated by a family of functions.

Generally any old new function can come along and manipulate a data-structure, if it does so in a way that the other functions can still understand it, then the function joins the family. Otherwise its a rogue function and a source of bugs.

Don't get me wrong there could be several families of functions warring over that data-structure with snitches, turn-coats, and double-agents everywhere. Its fine when they each have their own data-structure to play with, but when they share it... just imagine several crime families disagreeing over politics, it can become a mess really fast.

Given the mess extended function families can achieve, is there a way to encode the data structure so that rogue functions don't mess everything up? Yes, they are called Objects.

Are getters/setters useful in Objects? No.

The whole point of wrapping a data structure up in an object was to ensure that no rogue functions could exist. If the function wanted to join the family, it had to be thoroughly vetted first and then become part of the object.

The point/purpose of a getter and a setter is to allow functions outside of the object to alter the memory layout of the object directly. That sounds like an open door to permit in rogues...

The Edge Case

There are two situations were a public getter/setter make sense.

  • A portion of the data-structure within the object is managed by the object, but not controlled by the object.
  • An interface describing a high-level abstraction of a data-structure where some elements are expected to not be in control of the implementing object.

Containers and container interfaces are perfect examples of both of these two situations. The container manages the data-structures (linked-list, map, tree) internally but hands control over the specific element to all and sundry. The interface abstracts this and ignores the implementation entirely and describes just the expectations.

Unfortunately many implementations get this wrong and define the interface of these sorts of objects to give direct access to the actual object. Something like:

interface Container<T>
{
    typedef ...T... TRef; //<somehow make TRef to be a reference or pointer to the memory location of T
    TRef item(int index); 
}

This is broken. The implementations of Container must explicitly hand control of their internals over to whomever uses them. I've yet to see a mutable-value language where this is fine (languages with immutable-value semantics are by definition fine from a data-corruption perspective, but not necessarily from a data-spying perspective).

You can improve/correct the getters/setter by using only copy-semantics, or by using a proxy:

interface Proxy<T>
{
     operator T(); //<returns a copy
     ... operator ->(); //<permits a function call to be forwarded to an element
     Proxy<T> operator=(T); //< permits the specific element to be replaced/assigned by another T.
}

interface Container<T>
{
     Proxy<T> item(int index);
     T item(int index); //<When T is a copy of the original value.
     void item(int index, T new_value); //<where new_value is used to replace the old value
}

Arguably a rogue function could still play mayhem here (with enough effort most things are possible), but the copy-semantics and/or proxy reduces the chance for a number of errors.

  • overflow
  • underflow
  • interactions with the sub element are type-checked/type-checkable (in type lose languages this is a boon)
  • The actual element may or may not be memory resident.

Private Getters/Setters

This is the last bastion of getters and setters working on the type directly. In fact I wouldn't even call these getters and setters but accessors and manipulators.

In this context sometimes manipulating a specific portion of the data-structure always/almost-always/generally requires specific book keeping to occur. Say when you update the root of a tree the look-aside cache needs to be purged, or when you access the external data element, a lock needs to be gained/released. In these cases it make sense to apply the DRY principal and parcel those actions together.

Within the private context, its still possible for the other functions in the family to side-step these 'getters and setters' and manipulate the data structure. Hence why I think of them more as accessors and manipulators. You could access the data directly, or rely on another family member to get that part right.

Protected Getters/Setters

In a protected context, its not terribly different to a public context. Foreign possibly rogue functions want access to the data-structure. So no, if they exist they operate like public getters/setters.

Kain0_0
  • 16,561
0

From C++ experience, The setter/getter is helpful for 2 scenarios:

  1. if you have to perform sanity check before assigning value to the member like strings or array.
  2. it can be helpful when function overloading is needed like int value to bool assignment when -1 (or negative values) is false. and vice versa for getter.

Apart form that, security is a valid point but its importance is limited to very few development applications like login or db access related modules. Why bother coding extra when only few people uses your module?