Getters and Setters (C++)

Started by
27 comments, last by MaulingMonkey 18 years, 2 months ago
I'm with Extrarius here, think of term of actions, not in terms of data.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Advertisement
sometimes I just overload the get/set functions if Im using them. a void set function, and a get function that returns the type. But thats because in my head, having a function thats like window->height() sort of implies that im getting a value, not setting one. Whereas, doing something like window->height(600) to me, implies that Im setting a value. But other people might not read it like that in their head.
|aaap.penopticon.com| My website, including game projects. Collaboration/comments are welcome, please visit :)
Quote:Original post by Mr Awesome
This is a good point, and it is why I am considering removing the "set" prefix from my code as well. In ruby, getters and setters look exactly like public access (var = Foo.bar, Foo.bar = 17). If there is no confusion there, then I don't see how there can be confusion with getters and setters minus the somewhat redundant prefixes.
Umm... So Ruby's properties lead to no confusion because their usage looks exactly like public access. But in C++ if you drop the prefixes, the getters and setters still *don't* look like public access. I can't see how you don't see that this difference could lead to confusion.
I prefer to prefix Get and Set. I don't get how the code really looks "cleaner" by omitting them. Shorter, yes, easier to type, yes, but unless the user knows specifically that TacoBell::SauceFormula() is both the get and set, it's going to confuse the hell out of the person using it.

To each his own, however.
Quote:Original post by Anonymous Poster
Quote:Original post by Mr Awesome
This is a good point, and it is why I am considering removing the "set" prefix from my code as well. In ruby, getters and setters look exactly like public access (var = Foo.bar, Foo.bar = 17). If there is no confusion there, then I don't see how there can be confusion with getters and setters minus the somewhat redundant prefixes.
Umm... So Ruby's properties lead to no confusion because their usage looks exactly like public access. But in C++ if you drop the prefixes, the getters and setters still *don't* look like public access. I can't see how you don't see that this difference could lead to confusion.


They don't look exactly like public access, but the syntax is consistant without the prefixes, and wouldn't lead to being any more confusing.

You have:

public access:          set: foo.bar = baz      get: baz = foo.barC++ prefixless get/set: set: foo.bar( baz )     get: baz = foo.bar()ruby explicit(?) call:  set: foo.bar=( baz )    get: baz = foo.bar()prefixed get/set:       set: foo.set_bar( baz ) get: baz = foo.get_bar()


I fail to see how any of these could be ambiguous, and confused with one another (get/set that is). Which is the only reason that I can see cause for confusion that set/get prefixes would solve anyways, which is our current topic.

Quote:Original post by Flimflam
Shorter, yes, easier to type, yes, but unless the user knows specifically that TacoBell::SauceFormula() is both the get and set, it's going to confuse the hell out of the person using it.


I've never been confused by this kind of thing, since it's usually pretty obvious. Then again, I've never used such silly variable names in production code. Similarly, I've never been confused by Get/Set prefixes, since it's usually pretty obvious. Then again, I've never found them of much help, either.
See, Ruby doesn't use 'get' and 'set' prefixes because it's capable of working with properties natively. With C++, more specifically unmanaged C++, you don't have native access to property types. Now, if you were using managed C++, you might be able to get away with it. I know you can use properties in C#, so you wouldn't need the two prefixes in that case.

That being said, however, it would come down to the usage of the function. In the case of Extrarius, those functions performed actions, so it made more sense to use a function name with a verb. But, not all cases will be an action. Take this for example:

You have a class that encapsulates the properties of an employee working for you. This employee has a name, and just got married, so she changed her last name. If you were to drop the 'get' and 'set' prefixes from the accessor/mutator functions, those functions would now look quite ambiguous.

class Employee{  public:    void firstName(const std::string& sFirstName);    std::string firstName();    void lastName(const std::string& sLastName);    std::string lastName();  protected:    std::string    m_sFirstName;    std::string    m_sLastName;};


Now, to you, this wouldn't make much of a problem, since you're the one that's coded the class; however, think of someone with a little less experience than you, that has come into the project months later. If that person is used to using the prefixes in their code, they'd get confused by this.

Of course, this isn't the best example, since, if you know anything about accessors and mutators, this code will become immediately clear; but, that's just my point. You need to be aware of the people that will ultimately use your code. If it's just you, and nobody else will ever use your code, then use your best judgement. On the other hand, if there is a chance that someone else is going to use your code, you need to be aware of their experience, or lack thereof.

In my case, the library I'm designing for my college course is being developed for new programmers in mind. In this case, I would leave the 'get' and 'set' prefixes in to reinforce the usage of accessors and mutators.
Quote:Original post by Dorvo
Now, to you, this wouldn't make much of a problem, since you're the one that's coded the class; however, think of someone with a little less experience than you, that has come into the project months later. If that person is used to using the prefixes in their code, they'd get confused by this.


For about 5 seconds? Of course, if you switch to using Get/Set, they'll instead be confused by the Standard Library (iostream's rdbuf, std::stringstream::str, the numerous functions not prefixed with get/set everywhere). IMO, Get/Set tuples are over-emphisized anyways, over picking class-wide operations instead of focusing on individual members - or acknowledging a certain structure as plain old data - would be a better use of time. Plus, it's more consistant - and thus easy to remember. Consistant capitalization, verb emphisis, and so forth.
I don't understand why people think 'properties'(magic syntax to make what is apparently variable access act like function calls). Why should you hide what is really going on? If you want a public member variable, why not just make a public member variable?

Getters and Setters almost always break encapsulation and abstraction by saying "I'm a lazy object, so you'll have to update my state for me", which is against the principles of the OO paradigm.

The idea behind OO is that you(the programmer) tell objects to perform some action, and the object updates it's state to reflect that action (or returns failure, etc).
'Getters' make sense in a way because they provide a way to inspect the current state of an object, but care must be taken to avoid coupling the externally visible state and the implementation's representation.

For example, the image class mentioned in my previous post had a getter 'GetCurrentLine()'(instead of 'TopLine()' and 'BottomLine()') because it was originally designed to scroll automatically.The 'Current Line' was the last line it drew, and thus depended on the scroll direction - scrolling up meant new lines are appended to the bottom, and thus Current Line was on the bottom. This was not only confusing but also fragile. As the system was coming together, it was decided it would be to have the application to manually call a 'Scroll(DeltaNumLines)' function when it wanted to scroll, and in that context a 'CurrentLine' made less sense than it did before (which was admittedly very little). By making the accessors more generic (Top and Bottom line in addition to widget and image dimensions), the interface has been able to remain stable over many changes (including complete rewrites).

In general 'Setters' are a bad idea because you're eliminating abstraction. It's one thing to say 'ImageScroller.Scroll()' and quite another to say 'ImageScroller.SetLine(ImageScroller.GetLine() + ScrollSpeed); ImageScroller.Redraw();'. It might make sense to require the latter in some cases, but in the example I've given there isn't any reason for that - by definition it is the responsibility of the 'ImageScroller' to perform that function.

If you're creating classes like the one Dorvo listed, you should rethink your design. While an 'employee' could be called an object, the example is not an object in the usual OO sense because it's (conceptually) missing operations that manipulte the data. You might as well make 'employee' a struct with all-public members and no functions at all, because it's nothing more than a data record.
If you're not going to do any processing, there isn't a lot of reason to require a function call. Yes, planning ahead is good, but planning too far ahead for the indefinite and improbable future just obfuscates what's really going on.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Of course, if you already have public members, and discover you need to insert code when they are gotten/set, you can do it without changine client code.

class HasProperty{private:	int pm_int;public:	struct Property	{		int* data;		Property(int* data) : data(data) {}		operator int() 		{ 			std::cout << "int gotten\n";			return *data; 		}		int operator=(int rhs) 		{ 			std::cout << "int set\n";			*data = rhs; 			return *data; 		}	};	Property m_int;	HasProperty() : m_int(&pm_int) {}};HasProperty hp;int x = hp.m_int;hp.m_int = x;


Notice that the get behavior doesn't trigger unless you assign it to something.
Quote:Original post by Extrarius
I don't understand why people think 'properties'(magic syntax to make what is apparently variable access act like function calls). Why should you hide what is really going on? If you want a public member variable, why not just make a public member variable?
Because by using properties, you can change access functionality without affecting the code that uses the class. For example Dorvo's person-class could be changed to a remote access class with receives its data the first time you call a getter from some remote server, and perhaps stores the data to a local cache for faster future access. Of course, if you know that you'll never need such functionality from the class, you can just use public member variables (e.g. a 3d vector class).

This topic is closed to new replies.

Advertisement