Get and Set

Started by
14 comments, last by rip-off 12 years, 9 months ago
I have never had 'get' and 'set' explained in a way that I am able to understand what their purpose is, or why they are needed. I can go out there and found two different examples of code that work exactly the same way with one having properties that use 'get' and 'set', and the other doesn't. If you can do it without using them then it just seems kind of like a waste of time to use them. So, unless they are just archaic left overs from a bygone era, it is obvious they are useful, I just haven't had it explained in a way that I understand. I would greatly appreciate it if you guys could help me with this.
Advertisement
Typically you see Get and Set functions as methods of a class to make sure a member variable is set to a valid value, for example:

[source]
class Car
{
public:

void SetSelectedWheel (int wheel)
{
if (wheel >= 0 && wheel <= 3)
{
selectedwheel = wheel;
}
else
{
// error
}
}

int GetSelectedWheelState (void)
{
return wheelstate[selectedwheel]; // Will cause problems if selectedwheel is less than 0 or more than 3.
}

private:
int selectedwheel;
int wheelstate[4];
};
[/source]
Usually your class's data members are going to be set to private so nobody else can directly access the data in a way that isn't accepted by the class itself through its member functions. For a really basic class with private data members, you'll want a Get and Set so you can actually access those members.

Get and Set probably aren't at all necessary if your classes have more complex member functions to manipulate the data, however.

Usually your class's data members are going to be set to private so nobody else can directly access the data in a way that isn't accepted by the class itself through its member functions. For a really basic class with private data members, you'll want a Get and Set so you can actually access those members.

Get and Set probably aren't at all necessary if your classes have more complex member functions to manipulate the data, however.


Sorry, but I think this kind of vague explanation is probably what is giving a lot of people headaches out there. procgen's example on the other side is very good.

The main idea behind making attributes accessible through those selector methods instead of just declaring them public is that (taking also the constructor into account) you can verify that certain attributes will be in certain states at all time. If you use a class exclusively yourself it might seem like overhead (as you know which state is fine and which isn't), but it can help you prevent making errors.

If someone else uses that class (team members, users of your product, ...) you can make sure that they use your class as intended. I personally tend to see users as malicious opponents and it's worked quite well so far angry.gif

- Michael.

[quote name='irras' timestamp='1310696402' post='4835536']
Usually your class's data members are going to be set to private so nobody else can directly access the data in a way that isn't accepted by the class itself through its member functions. For a really basic class with private data members, you'll want a Get and Set so you can actually access those members.

Get and Set probably aren't at all necessary if your classes have more complex member functions to manipulate the data, however.


Sorry, but I think this kind of vague explanation is probably what is giving a lot of people headaches out there. procgen's example on the other side is very good.

The main idea behind making attributes accessible through those selector methods instead of just declaring them public is that (taking also the constructor into account) you can verify that certain attributes will be in certain states at all time. If you use a class exclusively yourself it might seem like overhead (as you know which state is fine and which isn't), but it can help you prevent making errors.

If someone else uses that class (team members, users of your product, ...) you can make sure that they use your class as intended. I personally tend to see users as malicious opponents and it's worked quite well so far angry.gif

- Michael.
[/quote]


YES! And that was a very nice example.

The problem with too many beginners tutorial on OOP written by beginners themselves is that the Get/Set is merely example that if you tried to access the variables directly, it will give error - and that's it. So please use Get/Set.

Andre LaMothe once complain about this, and normal struct with C function servers better. However, as the example suggest, there are time where OOP serves better once you know how to use it, and where to use it.

While the given example is a possible reason to use it, it is not a complete explanation. Often times, you have data members that you simply do not want the public to have access to. Consider the following implementation of a list:
(note that the code is probably not valid C++ or valid Java.I havent done any real c++ in 2 years now, but as it seems to be more of what people use (or C#) I will make an effort to use an example with it, though note that getters and setters seem to be much more common in java, I'll explain more later.)
public class MyStudentList {
Student** data;
int size;
int capacity;
MyStudentList() {
size = 0;
capacity = 2;
data = new Student*[capacity];
}
~MyStudentList() {
clearData();
}
void add(Student s) {
if(size == capacity)
setCapacity(capacity*2);
data[size++] = new Student(s);
}
void setCapacity(int n) {
if (n == capacity) // already there, dont do unnecessary work
return true;
if (n < size || n <= 0) // dont let the user lose data by resizing too small
return false;
int oldCap = capacity;
capacity = n;
Student** temp = new Student*[capacity];
for(int i=0; i<oldCap; i++)
temp = data;
clearData();
data = temp;
}
void clearData() {
for(int i=0; i<size; i++)
delete data;
delete [] data;
}
};



Note that I left out visibility modifiers (public, protected, and private).

It is obvious that we want some of these members to be completely invisible to people who use this list. For example, the following code should be prevented, as it would break the program, and most people understand this right away:
void main() {
MyStudentList list; list.add(Student("Suzan"));
list.add(Student("John"));
list.capacity = 9001;
list.add(Student("Kevin"));
}


The code would trigger a memory access violation on the third add, because it thinks the current array is capable of holding 9001 students, when it was only declared with 2 slots. It is pretty easy to see here that we don't want people to ever see the capacity, though we might want to let them know it starts at 2 and doubles every time it will be exceeded, and never shrinks.

However, if we make it strictly private, then the user could never peek in and see what the capacity currently is. This is where a getter comes in. It would be nice to be able to let the user look at the current capacity, without actually having the ability to change it. Going down that line, it would also be nice to allow the user to change the capacity. However, changing the capacity is not as simple as "capacity = 9001", there is a process to be followed, as evidenced by the setCapacity(int n) function.

I could prepare a pretty simple example for a situation where a get isn't that simple too, but I'll just describe it. What if you don't want to store the size of your data (as with a linked list, for example)? You could just make it so the "getSize()" function iterates through the entire list and counts it manually when the size function is called, and returns the result. Useful if you really need to trim 4 bytes out of your list, but it's a pretty impractical example. The point being, you could have things that you want people to be able to get that might not be stored that require a process to retrieve. Also they might be private as per the guideline above regarding capacity.

So, to sum up, you need setters if there is error checking to be done when setting to a particular value (above -- people cannot resize an array to a negative/zero size OR a size smaller than the current number of data objects), or if the value is private for some other reason I can't think of at the moment. That one is the most prevalent one. You need getters when something is private under the guidelines for needing setters, or if the number itself is not actually stored and must be computed each time the function is called. Sorry I don't have a more practical example for that--the primary need for them is when the number is private because of requiring a getter though, so understanding that reason is much more important.

Maybe that helps clear it up. Maybe not. I sure as hell am not rereading that wall of text I just concocted. I hope there aren't any really stupid errors in the code. ::nervous::

I have never had 'get' and 'set' explained in a way that I am able to understand what their purpose is, or why they are needed.


They are needed by the auto-generated ORM code on top of which Java applications were built. The get/set functionality was mandated by JavaBeans specification as part of JEE. The original get/set had first wide-spread use in VCL in Delphi, where they were implemented as a lazily evaluated properties. Idiom there was:int set(int newValue) {
if (newValue != value) {
value = newValue;
notifyChange(this, value);
}
}

inf get() {
if (isDirty) {
recompute();
}
return value;
}
Both of these can be solved much more elegantly in most languages, some are even built implicitly around such assumptions. C# at least offers different constructs to achieve same functionality and with features like LINQ they aren't needed anymore.

In JEE, they were part of reflection and code generation facilities. Tool would go over source code and find matching get/set pairs. If code contained: T getFoo() and setFoo(T), the UI designer or design tool would show 'Foo' as property. If set was missing, it was read-only property. This is one of those decisions which made Java a disaster - rather than introducing properties, they settled for convention.

Next was ORM database mapping. Since it was designed to be automatically generated, in order to hide any implementation details, mapped properties were exposed via get/set so internal variables could remain hidden. All of this is automatically generated and a lot of production code contains nothing but thousands upon thousands of such classes.


Since generations of programmers were trained to use that approach and since tools were built around this concept, it slowly seeped into education and eventually had to be replicated across C# as well, since this is what everyone expected code to look like.

A self-fulfilling prophecy of sorts.

Various argumentations on how it "improves encapsulation" and similar hold absolutely no merit. The get/set idiom is a workaround for missing features of language.

So, unless they are just archaic left overs from a bygone era[/quote]Strangely enough, they are, the era just isn't gone and will remain around for decades.

it is obvious they are useful[/quote]They are almost exclusively an artefact in Java and C# libraries. Since those are the predominant languages used today, the idioms from them seep into C++ as well.

Most dynamic languages offer first-class mechanism that makes explicit getters irrelevant. First-class language properties also replace them, but few mainstream languages expose them in such explicit manner - C# get/set are mostly syntactic sugar.

public void somefunction(int &blah)
{
something = blah + somethingelse;
//Random state change of passed reference for example's sake
++blah;
}



class MyClass1
{
public:
int SUPER_IMPORTANT_DATA;
}



class MyClass2
{
public:
int GetImportantData() const {return SUPER_IMPORTANT_DATA};
void SetImportantData(int blah) {SUPER_IMPORTANT_DATA = blah};
private:
int SUPER_IMPORTANT_DATA;
}



MyClass1 class1 = new MyClass1(7); //assume I made a constructor that sets SUPER_IMPORTANT_DATA .
MyClass2 class2 = new MyClass2(7); //SUPER_IMPORTANT_DATA = 7
somefunction(class1.SUPER_IMPORTANT_DATA);//SUPER_IMPORTANT_DATA = 8
somefunction(class2.GetImportantData()); //SUPER_IMPORTANT_DATA = 7


Didn't double check this, so I hope it gets the point across.
As said before, the get set properties (specially the set) main purpose is to add additional code to the process of value assignation and retrieval, verification, change of format, special cases, debug outputs, are examples of what you might want to be adding in those methods.

What is sometimes confusing is how is this any different than creating functions that get or set the variable's value?
Well, the thing is these particular constructs usually have other uses in managed languages like C# (I believe this applies the same way on action script / flash).
There is usually some way to access a list of attributes, which would include any member variable that has those methods and allows you to read and write to those variables without the need of explicitly knowing the final type of the object you are operating over, this is usually used to create automatic parsers that do not need to be extended for each and every type of object you might want to parse, since it has the attributes list it can read all the properties dynamically and save them to a file, and then read the file and push the values into a new instance of the object without really knowing what it is.


Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


Get and set functions are, generally speaking, contrary to object oriented design. They encourage code that reaches into an object's guts and starts messing with the values. They encourage creating classes that act as dumb containers of data, rather than rich objects with behaviour. Set functions mostly mandate the existence of a particular member, where it should be hidden from the client if possible instead. See the law of demeter for example of the kinds of abuse this leads to.

Many programmers learned Java, which uses "get" and "set" methods heavily. Until they grow out of it, they have a mindset of writing a class that involves adding a get and set method for every field they add. The result is usually spaghetti code with object logic leaks out into the interfaces of clients, and essentially makes it impossible to create and enforce complex invariants (in particular, relationships between field values).

Think about the C++ standard library - there are no "get" and "set" functions. It exposes read-only access to many interesting properties, but only those that "make sense". A string has a length, and you can access the characters at any particular index.

This topic is closed to new replies.

Advertisement