getters & setters are bad, design patterns etc.

Pages: 1234567
^yes^ take et leave et. mkay?
mm( mm( mm( mm( a, b ), c ), d ), e)


I would think you'd write it more like this to increase readability:
This would involve a function with a variable length parameter defined.
result = matrix.multiply(a, b, c, d, e)
Last edited on
┬┐member function? (oh right, java)
if( vector.subtract( matrix.multiply(m,x), b ).norm() < TOL )
closed account (o1vk4iN6)
@Zaita

Ah yah, wouldn't have thought of that (didn't even know Java had variable length parameters). Though I guess I was trying to imitate operator overloading too much lol.
For my math library I found operator overloading to be a must - surprisingly, not for readability reasons, but for consistency and the ability to actually remember how the function is named.

In the beginning I used mixed paradigm: sometimes call multiplication operator*= sometimes call it Multiply, sometimes call it MultiplyBy, sometimes MultiplyByConstant, MultiplyByVector (for different input types), etc. Similar story with the other operators.

Then I ran into two major problems. First was that when I wrote template functions, I had to use one name for the multiplication/addition/subtraction/assignment operators. But most importantly I ran into human memory issues: operator*= has unquestionable and unmistakable semantics, so it was easy to remember the function names (you can't get autocomplete for the member functions of the unknown template parameter code::blocks fails to give correct autocomplete with templates).

tition wrote:
True, readOnlyPrice is public, but, because of its name, every sane programmer will think twice before modifying it, and if not, well, you will know who to fire first.

That's incredibly obtuse. "We don't need to use language features that enforce access restrictions, because we name our variables readOnlyXXX, and that way we can save a whole line of code!" Surely the sane programmers have already left.


Well, I was complaining from the lack of the programming feature I need: read only access public, write access private. You are telling me that I should impose restrictions on my code that do not conform to my requirements, and create extra work for me. Instead, you should tell me which language feature serves my purpose.

The notion of changing your requirements to meet the specific design decisions/imperfections/flaws of the language is a lot more obtuse than the dirtiest programming hack that serves your purpose.
Last edited on
@tition, most definitely agree with the 80% of your comment that I read.
Forgive my ignorance, but I don't understand why getters and setters are bad. Almost every library I have ever used has getters and setters for interacting with objects and data. This just adds to me not understanding why they are bad.
You just want to think about hiding the implantation as much as you can without incurring disadvantages.

Getters and setters, I think, beat public access the vast majority of the time in terms of design. Even for a point class, or shape, or vector. Consider that there could be restrictions imposed on the values you are allowed to set the members to. If you use getters and setters, then you are able to handle the ways in which they are used in a flexible way.

Think also about a fraction class. Is there something wrong with not using setters? What happens if you set the denominator to 0?

There are certain cases where you can be sure that encapsulation does not matter so much, or where you are sure you wont need flexibility or restrictions on how variables are used or set.

Last edited on
closed account (3qX21hU5)
Forgive my ignorance, but I don't understand why getters and setters are bad. Almost every library I have ever used has getters and setters for interacting with objects and data. This just adds to me not understanding why they are bad.


I would say the rule of thumb is if they are used correctly they are fine to use, but if they are used incorrectly they aren't. I would also suggest not to overuse them.

Generally it all depends on what type of class you are making. You want to make the class as easy to use as possible for the user of your class, but you also want to put safeguards in so the user can't break the implementation of your class.

So use your best judgement when you are trying to think whether or not a private member needs a getter or setter. Sometimes it will do more harm then good, other times it is a must.

The only time I believe getters and setter are bad practice is when you just go into a class and define one for every single member in that class even when they aren't needed (Surprisingly I see this a lot, though mostly with beginners that are just starting classes).
The only time I believe getters and setter are bad practice is when you just go into a class and define one for every single member in that class even when they aren't needed (Surprisingly I see this a lot, though mostly with beginners that are just starting classes).

Bad part is that most colleges and books teach you to make setters and getters for every member in beginner classes and never break that habit in advanced classes or later chapters of the books.

ie:

1
2
3
4
5
6
7
8
9
10
11
12
class ClassName{
     string name;
     int age;
     int weight;
public:
     void setName(string strName);
     void setAge(int iAge);
     void setWeight(int iWeight);
     string getName() const { return name; }
     int getAge() const { return age; }
     int getWeight() const { return weight; }
};


I'm lazy though and I do things like:
 
void setData(string strName, int iAge, int iWeight); 


I usually use references in place of getters though.
Here's what I would consider a 'correct' version of that class, changing only the things relevant to this discussion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Person
{
    //obviously you would have type aliases and such for these
    std::string name;
    int age;
    int weight;
public:
    std::string const &Name;
    int const &Age;
    int const &Weight;

    Person(std::string name, int age, int pounds)
    : name(name)
    , age(age)
    , weight(pounds)
    , Name(name)
    , Age(age)
    , Weight(weight)
    {
    }

    void PassTime(int years) //affects age and weight
    {
        age += years;
        weight -= weight/(10/years + 1);
    }
    void EatFood(int pounds) //affects weight
    {
        weight += pounds;
    }
    void Exercise(int minutes) //affects weight
    {
        weight -= minutes/30;
    }
};
This is a bad example though because all the members need to be accessible - a better example would have members that did not ever need to be public but were still part of the state.
Last edited on
closed account (3qX21hU5)
Bad part is that most colleges and books teach you to make setters and getters for every member in beginner classes and never break that habit in advanced classes or later chapters of the books


I personally haven't read a book that has advocated that, though I am sure there are some out there.

Abstraction is all about making your types fit your needs better. Like in LB's example which could be used to manage a person in a simulation game or something. He is creating the getters and setters for a specific task that they can be used for(Like gaining weight, getting older, ect.). This way makes it much more easy to think of the class as a abstract object when using it.

His example looks very much like your example but there is major differences in my opinion (Which everyone will think differently on this subject).
Last edited on
I would remove age field and replace it with DoB. And add member function which allows to find age at arbitrary point of time.
And depending on what I designed this class for I might add field which will store pointer to function which will get weight change dynamics abd do something with it.
Last edited on
@MiiNiPaa I did that originally but I wanted to show just what I would change in terms of interacting with the class.
This is a bad example though because all the members need to be accessible - a better example would have members that did not ever need to be public but were still part of the state.


If you want to compare getters with const reference members, it can't be done favorably. The internal type is published with the const reference members. It is not with getters. In other words you get all of the "bad design" stigma with none of the resultant flexibility.

As a matter of illustration with regard to MiiNiPaa's comment about DoB, with getters you could change the internal representation to do that without affecting the existing interface. Using const reference members, you cannot.
closed account (o1vk4iN6)
LB wrote:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person
{
    //obviously you would have type aliases and such for these
    std::string name;
    int age;
    int weight;
public:
    std::string const &Name;
    int const &Age;
    int const &Weight;

    Person(std::string name, int age, int pounds)
    : name(name)
    , age(age)
    , weight(pounds)
    , Name(name)
    , Age(age)
    , Weight(weight)
    {
    }
};



Is that really better than just having getters ? Here it isn't just design any more, you are reducing performance and adding overhead.
Setters and getters can't be all that bad. It doesn't call them that, but even the tutorial on this site for classes uses setters and getters:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// classes example
#include <iostream>
using namespace std;

class CRectangle {
    int x, y;
  public:
    void set_values (int,int);  // setter
    int area () {return (x*y);}   // getter
};

void CRectangle::set_values (int a, int b) {
  x = a;
  y = b;
}

int main () {
  CRectangle rect;
  rect.set_values (3,4);
  cout << "area: " << rect.area();
  return 0;
}

They only get dropped when it moves to the example of constructors and destructors. With class data you always have to have a way of setting it and then getting it so it is odd to me that people say they are bad.
A situation I had where getters were a must (and setters were not really directly needed).

I have a math data structure (``a finite group'') I identify using 9 numbers. From these 9 numbers, using ~700 000 arithmetic operations, I can compute a 10 by 10 element table I need. It happens so that the rows of the table can be computed somewhat independently of one another.

So I made the ``finite group'' be ``compute-on-demand''. For each row of the table, I have a bool variable if it's been computed. To get a table row, my getter checks whether the row is computed, and only if not, calls the function computing it.

I'd say there is no better way of doing this without the getter paradigm.
Last edited on
@BHXSpecter: That looks fine, a poor use of getters/setters would be if you added:
1
2
3
4
GetX()
GetY()
SetX(...)
SetY(...)
to CRectangle.
Pages: 1234567