Sign in to follow this  
TheDodo

Get and Set

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
[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.
[/quote]

Sorry, but I think this kind of vague explanation is probably what is giving a lot of people headaches out there. [i]procgen[/i]'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 [b]verify that certain attributes will be in certain states[/b] 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 [img]http://public.gamedev.net/public/style_emoticons/default/angry.gif[/img]

- Michael.

Share this post


Link to post
Share on other sites
[quote name='Michael N.' timestamp='1310699351' post='4835545']
[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.
[/quote]

Sorry, but I think this kind of vague explanation is probably what is giving a lot of people headaches out there. [i]procgen[/i]'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 [b]verify that certain attributes will be in certain states[/b] 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 [img]http://public.gamedev.net/public/style_emoticons/default/angry.gif[/img]

- 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.

Share this post


Link to post
Share on other sites
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.)
[code]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[i] = data[i];
clearData();
data = temp;
}
void clearData() {
for(int i=0; i<size; i++)
delete data[i];
delete [] data;
}
};[/code]


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:
[code]void main() {
MyStudentList list; list.add(Student("Suzan"));
list.add(Student("John"));
list.capacity = 9001;
list.add(Student("Kevin"));
}[/code]

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::

Share this post


Link to post
Share on other sites
[quote name='TheDodo' timestamp='1310693590' post='4835520']
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.[/quote]

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:[code]int set(int newValue) {
if (newValue != value) {
value = newValue;
notifyChange(this, value);
}
}

inf get() {
if (isDirty) {
recompute();
}
return value;
}[/code]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.

[quote]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.

[quote]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.

Share this post


Link to post
Share on other sites
[code]
public void somefunction(int &blah)
{
something = blah + somethingelse;
//Random state change of passed reference for example's sake
++blah;
}
[/code]

[code]
class MyClass1
{
public:
int SUPER_IMPORTANT_DATA;
}
[/code]

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

[code]
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
[/code]

Didn't double check this, so I hope it gets the point across.

Share this post


Link to post
Share on other sites
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.


Share this post


Link to post
Share on other sites
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 [b]behaviour[/b]. 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.

Share this post


Link to post
Share on other sites
Rip-off, I agree get set functions have a high potential for abuse and misuse and facilitate messy code, but so do many c++ features, every language everywhere has ways of being abused and misused, dangerous features are usually there for a reason and no feature is intrinsicly evil... except maybe c++ arrays :P

The important thing is to figure out what is the proper way to use them and when are they useful, as well as how not to use them to avoid creating bad code.

Share this post


Link to post
Share on other sites
Like rip-off stated get and set are very abused. With statements like use get and set no matter what it creates the mentality that you should always use get and set and this is very bad programming design. The purpose of an object is to encapsulate a behavior not be a container for data. You can think of the data as a necessary side effect to creating behavior.

The ultimate goal is to hide all of the guts period and only expose what absolutely has to be exposed and it should typical be exposed in a read only manner because modifying that data will have an adverse side effects on the goal of the objects behavior. So when designing your objects; design them in a way to not expose internal data and if you do by some chance need to expose data expose it as read only. If you need to modify data do it through a member function designed to manipulate that data in a meaningful way don't just use a Set function that is bad; instead turn the manipulation of that data into an actual behavior.

The idea is if you have player object that has a position it is ok to have a GetPosition because a drawing function might need to know the position to draw at. But when you need to move the player don't do it through a SetPosition() do it through a Member Function called Move. This turns into a behavior instead of data manipulation because the client is not manipulating the data it is asking for the object to execute a behavior. The client does not care about the data and it should not care about the data only the behavior.

Share this post


Link to post
Share on other sites
Thank you, I think collectively you guys have explained it well enough, and left me with some things to think about. If there is anyone late to the party that thinks they have a better answer though go ahead and say it, if it doesn't help me it might help another beginner lurking around.

Share this post


Link to post
Share on other sites
I kinda covered this in a different post that others found legiable, so I'll repeat it. [url="http://www.gamedev.net/topic/603568-need-help-understanding-encapsulation-properties-and-fields-in-c/page__view__findpost__p__4820108"]Source post here.[/url]



------------------------------------------------------------


The terminology can be a bit confusing. You are close, but off by a bit.

In the simplest terms, think of "Fields" as the data of a class. The availability of a field to other classes has nothing to do with properties however, that instead is the roll of the modifiers.

A field is composed of at least one modifer, a type then a variable name, for example:

[code]public int myInteger;[/code]

The modifier in this case is [b]public[/b] which essentially means that other classes can access that data value. As telastyn said, other modifiers include [b]private[/b], [b]internal, protected [/b]& [b]protected internal. [/b] For now, lets just focus on public and private. Public means other classes can access, private means they don't have access. The other modifiers are mostly used when working with inheritance ( deriving other objects from your object ) and you can cross the bridge when you get to it. [b]static [/b] and [b]readonly [/b] also exist as modifiers, but lets just ignore that fact for now!


So, in summary, a field is a piece of data within a class and the fields modifier determines how that data can be accessed.


Now properties are super straight forward, just a bit oddly named. In just about every language, its pretty common to have private fields ( or member variables, choose your naming poison ) with public accessor functions. This means your data is [b]private [/b]to the class, but is accessed through a [b]public [/b]function.

Often it would look something like this:

[code]
class Demo
{
private int somePrivateInt; // field, not publicly accessible

public int GetSomePrivateInt()
{
return somePrivateInt;
}
}
[/code]

This kind of code became so common, C# provided a short cut version, the property, which looks like this:

[code]
class Demo
{
private int somePrivateInt;

public int SomePrivateInt
{
get { return somePrivateInt; }
set { somePrivateInt = value; }
}
}
[/code]

In this demo SomePrivateInt is a property that accesses somePrivateInt.

You may be thinking to yourself, why the hell would I want to do this? First off, it makes changing your class down the road much simpler, it adds one layer of abstraction between the other code consuming your code and your codes internal logic. For example, lets say you had a variable but somewhere down the road, you wanted it incremented every time you accessed it, its as simple as:


[code]
class Demo
{
private int somePrivateInt;

public int SomePrivateInt
{
get { return ++somePrivateInt; }
}
}
[/code]

Now, as you can see, the functionality of your class changed, but to any code calling Demo, it all seems exactly the same. Another thing to notice in the above code is, I removed the set {} code. This effectively makes somePrivateInt read only. You can choose to only implement set or get, and effectively make the accessed field read or write only.


Of course, properties don't have to be accessors for existing fields, they also can be computed values. Consider the following example:

[code]
class Rectangle
{
public int Width;
public int Height;

public int Area
{
get { return Width * Height; }
}
}
[/code]

In this case, the property is calculated on the fly.



Finally, you can use properties to defer initialization. Consider:

[code]
class Renderer
{
private SceneGraph mySceneGraph;

public SceneGraph MySceneGraph
{
get
{
if(mySceneGraph == null)
mySceneGraph = new SceneGraph();
return mySceneGraph;
}
}
}
[/code]

In this particular case, the allocation of mySceneGraph is deferred until the first time it is used. Note, the property doesnt HAVE to be the same name as what it accesses with the first letter capitalized, it's just a pretty standard naming convention.


Now, one very final example is the auto property. Back to our very first example:


[code]
class Demo
{
private int somePrivateInt;

public int SomePrivateInt
{
get { return somePrivateInt; }
set { somePrivateInt = value; }
}
}
[/code]

This kind of code is very very very common, so common in fact that C# 3 implemented a short hand version.


[code]
class Demo
{
public int SomePrivateInt
{
get;set;
}
}
[/code]

It has the exact same effect as the earlier demo, just a lot less typing.

Share this post


Link to post
Share on other sites
[quote name='rip-off' timestamp='1310740156' post='4835671']
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 [b]behaviour[/b]. 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.
[/quote]

This I disagree with. Getter/setter methods are no more anti-OO than public variables. In fact they are MORE object oriented in a manner of speaking, as they can provide an interface that can work as a black box externally, but can be changed internally. This is the essense of encapsulation, one of the pillars of object oriented programming.


Like any feature though, it can be abused.



To a new developer, there isn't really a reason to avoid get/set methods; they aren't persay "bad".

Share this post


Link to post
Share on other sites
[quote]
In fact they are MORE object oriented in a manner of speaking, as they can provide an interface that can work as a black box externally, but can be changed internally.
[/quote]
They are still quite rigid though. With most set member functions, all you can do is some simple validation on the incoming value. "Get" member functions are generally OK, but shouldn't be created unless they actually need to be used.

The main problem with get/set is that people end up writing:
[code]
player.setHealth(player.getHealth() + 1);
[/code]
This is object logic leaking beyond its interface.

Great, you can validate the health is never greater than $MAX_HEALTH and you can trigger some code when the player's health drops to zero, but this doesn't change the fact that your object lacks behaviour. There is little intent present in that interface, whereas a "heal()" member function is much nicer. I also prefer player.health() to something like player.getHealth().

I'm not saying they [b]never[/b] have a use. Just that they should be the last thing you consider adding, and even then only if truly necessary.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this