public member variable vs. get/set functions

W

W Karas

The main purpose of private members is to provide some level of compile time checking for the rules of use of an object that must be followed, in order to keep the object in a valid state.

Given that, a private member variable with (simple, public) get/set functions just seems like pointless code bloat. It provides no additional protection against putting the object in a bad state than having the member variable be public.

Some (perhaps Smalltalk fans) argue that it's very rare that simply settinga member variable should properly be part of an objects public interface. Therefore, it's best to follow the rule of thumb that all member variablesshould be private.

It can also be argued that it is often important, for code maintenance, to be able to quickly identify external changes to a member variable, as opposed to read access to the variable. A counter-argument is that some sort ofcode browsing tool should be available to prevent the need to bloat the code in order to highlight this distinction.

In some cases, it could be likely that the get/set function would eventually do more than simple get/set a single member variable. That would be a clear case where keeping the member variable private would be the correct choice. But, as I have seen Dr. Bjarne argue, it's easy to go overboard with future-safety.

Your thoughts?
 
M

Marcel Müller

The main purpose of private members is to provide some level of compile time checking for the rules of use of an object that must be followed, in order to keep the object in a valid state.

Given that, a private member variable with (simple, public) get/set functions just seems like pointless code bloat. It provides no additional protection against putting the object in a bad state than having the member variable be public.

It also creates no overhead in an optimized build as long as your
getter/setter is implemented inline.
Some (perhaps Smalltalk fans) argue that it's very rare that simply setting a member variable should properly be part of an objects public interface. Therefore, it's best to follow the rule of thumb that all member variables should be private.

It can also be argued that it is often important, for code maintenance, to be able to quickly identify external changes to a member variable, as opposed to read access to the variable. A counter-argument is that some sort of code browsing tool should be available to prevent the need to bloat the code in order to highlight this distinction.

Eclipse CDT can mostly distinguish between read and write access in the
references view.
In some cases, it could be likely that the get/set function would eventually do more than simple get/set a single member variable. That would be a clear case where keeping the member variable private would be the correct choice. But, as I have seen Dr. Bjarne argue, it's easy to go overboard with future-safety.

If you intend to change the behavior in future versions using
getters/setters might keep source code compatibility.
Your thoughts?

I usually do not use simple getters/setters. But I usually also do not
need public member variables, except for const ones.


Marcel
 
V

Victor Bazarov

The main purpose of private members is to provide some level of
compile time checking for the rules of use of an object that must be
followed, in order to keep the object in a valid state.

Given that, a private member variable with (simple, public) get/set
functions just seems like pointless code bloat. It provides no
additional protection against putting the object in a bad state than
having the member variable be public.

"Simple"? You mean, "obvious" or "apparent"? Well, perhaps. You can
call it a "placeholder", though, and then it's not necessarily so simple
anymore. Later you can decide to make it more complex, add validation
(if that's what you're after), and then it's not *at all* the same as
having a public member.
Some (perhaps Smalltalk fans) argue that it's very rare that simply
setting a member variable should properly be part of an objects
public interface. Therefore, it's best to follow the rule of thumb
that all member variables should be private.

It can also be argued that it is often important, for code
maintenance, to be able to quickly identify external changes to a
member variable, as opposed to read access to the variable. A
counter-argument is that some sort of code browsing tool should be
available to prevent the need to bloat the code in order to highlight
this distinction.

If those getter/setter functions are "simple", as you call them, then
the "code bloat" is not significant, and from the code maintenance POV
it's better to have a function that gets inlined by the compiler than
have the name of the member data strewn around the rest of the user
code, which also carries the danger of pointer or reference retention
and can cause other kinds of trouble.
In some cases, it could be likely that the get/set function would
eventually do more than simple get/set a single member variable.
That would be a clear case where keeping the member variable private
would be the correct choice. But, as I have seen Dr. Bjarne argue,
it's easy to go overboard with future-safety.

Your thoughts?

It's easy to go overboard with anything one does. Still, a little
planning ahead goes usually a long way. If you think you need to ask
the "why do it if we don't need it" question, then don't forget to ask
the "what's it going to cost to add it later if we do need it" as well.

V
 
W

W Karas

It also creates no overhead in an optimized build as long as your getter/setter is implemented inline.

Correct in that it creates no object code bloat. But does still create source code bloat (size increase).
 
C

Chris Uzdavinis

Correct in that it creates no object code bloat. But does still create source code bloat (size increase).


It has been said to not worry so much about the implementation (as that canalways be fixed if it's wrong) but to worry about the interface. Get thatwrong and you may be stuck forever.

Don't forget about the possibility of changing the underlying representation of your data. If you have public data then you are permanently locked into that implementation (unless you are lucky enough to be able to track down every use of your class. Unless you're your only customer, that can be very difficult.)

It's usually a bad idea to expose implementation details in your interface because once exposed they cannot be changed. If you realize you made a poor decision and want to represent them differently, too bad.


If there is even the slightest chance that in the future you may need to intervene with the returned value, or set a breakpoint, or count the number of accesses, add validation, or do any of a handful of other things with that point of access of your data, with the accessors you can.

A few lines of inline accessor code buys you so much, and is IMHO a very low price to pay.

Chris


chris
 
W

W Karas

.
If there is even the slightest chance that in the future you may need to intervene with the returned value, or set a breakpoint, or count the numberof accesses, add validation, or do any of a handful of other things with that point of access of your data, with the accessors you can.

A few lines of inline accessor code buys you so much, and is IMHO a very low price to pay.
....

The point about breakpoints is a good one. But again, that can be seen as bad compensation for bad tools. The debugger should support data breakpoints. Also, you could temporarily rewrite:

int i;

as:

struct I { int i; operator int & () { return(i); } }; I i;
 
W

W Karas

.
A few lines of inline accessor code buys you so much, and is IMHO a very low price to pay.
....

class Point
{
private: double x, y;
public:
void set_x(double x_) { x = x_; }
double get_x() { return(x); }
void set_y(double y_) { y = y_; }
double get_y() { return(y); }
};

The fact that you probably threw up a little in your mouth when you read this code indicates why I think you should consider maintaining some flexibility in your point of view on this.
 
I

Ian Collins

W said:
.
....

class Point { private: double x, y; public: void set_x(double x_) { x
= x_; } double get_x() { return(x); } void set_y(double y_) { y = y_;
} double get_y() { return(y); } };

The fact that you probably threw up a little in your mouth when you
read this code indicates why I think you should consider maintaining
some flexibility in your point of view on this.

* Please clean up the mess that shite google interface makes of you
quotes. *

If you have retained more of the original context, you might have
appreciated the point Chris Uzdavinis made.

Ignoring the case where point is just a trivial struct, one might have

class Point
{
double x, y;

void sanityCheck( double );

public:

void y(double y_) { sanityCheck(y_); y = y_; }
void x(double x_) { sanityCheck(x_); x = x_; }

double x() const { return(x); }
double y() const { return(y); }
};
 
Ö

Öö Tiib

Some (perhaps Smalltalk fans) argue that it's very rare that simply setting a member variable
should properly be part of an objects public interface. Therefore, it's best to follow the rule
of thumb that all member variables should be private.

What is that "simply setting"? Can you bring lot of "simply setting a member variable" examples
from C++ standard library? If you have difficulties then maybe C++ library is made by
"Smalltalk fans"?
 
J

Jorgen Grahn

It has been said to not worry so much about the implementation (as
that can always be fixed if it's wrong) but to worry about the
interface. Get that wrong and you may be stuck forever.

But that's almost never true! It /is/ true if you're writing
libraries and handing them out, but almost noone does that.

It took me many years to realize that
(a) I'm writing programs, not building a cathedral
(b) I can always refactor something later if it's important to.
(c) The static nature of C++ makes (b) rather easy: change the
interface; hack the client code until it compiles again;
change the inner implementation until that also compiles again.

/Jorgen
 
W

W Karas

But that's almost never true! It /is/ true if you're writing
libraries and handing them out, but almost noone does that.
It took me many years to realize that
(a) I'm writing programs, not building a cathedral
(b) I can always refactor something later if it's important to.
(c) The static nature of C++ makes (b) rather easy: change the
interface; hack the client code until it compiles again;
change the inner implementation until that also compiles again.
....

But what you're saying seems to go against the O-O philosophy. Which says you should try to build your program as a set of cooperating objects. The objects should have a "natural" interface that can be based on the nature of the object, rather than the particular purpose of the program. Thus, this interface can be reused (ideally) in all programs involving objects of this type. This implies that the interface is used in lots of places. Implying there is a big multiplier from the amount of interface change to the amount of other consequential change.
 
J

Jorgen Grahn

(b) can become difficult when the API in question is provided by
a third-party library, for which one does not have source. Using
the getter-setter paradigm in the library allows the library vendor
to make enhancements to the API without actually changing it.

I don't quite understand what you're getting at here ... note that
I explicitly left out the library designer case.

/Jorgen
 
J

Jorgen Grahn

But what you're saying seems to go against the O-O philosophy.

Maybe. I don't feel I have to follow someone else's philosophy.
Besides, it's not 1992 anymore. People don't seem to take object
orientation that seriously.
Which says you should try to build your program as a set of
cooperating objects.

So far, so good.
The objects should have a "natural" interface
that can be based on the nature of the object, rather than the
particular purpose of the program.

But that last part ... that idea has caused so much damage! I have not
seen it stated explicitly before, but I've seen a lot of designs
warped by it.

A program should be like a movie set: it may look like a western town
or the Death Star or whatever, but the parts not shown on film are
never built!
Thus, this interface can be reused
(ideally) in all programs involving objects of this type. This
implies that the interface is used in lots of places. Implying there
is a big multiplier from the amount of interface change to the amount
of other consequential change.

Yes, but as we all know that's untrue, unless you're a successful
library designer.

Are you trolling me in a mild way, by the way? Do you have an opinion
on this subject?

/Jorgen
 
W

W Karas

Maybe. I don't feel I have to follow someone else's philosophy.

OK, that's safe to do in the nicer countries of the world.
Besides, it's not 1992 anymore. People don't seem to take object
orientation that seriously.


So far, so good.


But that last part ... that idea has caused so much damage! I have not
seen it stated explicitly before, but I've seen a lot of designs
warped by it.

The existence of non-nail fasteners implies neither that all nor none of one's tools should be hammers.

Sometimes you'd define the full "natural" interface and do a full implementation.

Sometimes you'd define the full "natural" interface, but do not implement the parts not immediately needed.

Sometimes you'd define just the part of the "natural" interface that you need at that time.

Sometime your boss won't let you leave the building till it's done, so you just worry about the program you're currently working on.

Almost any virtue in excess becomes a vice. Fortunately, Dr. Bjarne is aware of this, so in C++ functions that are not objects do not have to pretend that they are.
A program should be like a movie set: it may look like a western town
or the Death Star or whatever, but the parts not shown on film are
never built!

Unless the other side of the building is likely to appear in your next movie.
Yes, but as we all know that's untrue, unless you're a successful
library designer.

O-O and generic programming work to make successful library designers of us all.
Are you trolling me in a mild way, by the way? Do you have an opinion
on this subject?

Stop troll-trolling.
 
W

W Karas

Not at all!








True, but insights change.







The promise of re-use. How well has that worked for you?






How often do you really re-use an interface without copy-paste of the

implementation?







In reality, objects are often tied to a specific program. A set of

programs may use a custom library, and then the use of the interface is a

bit higher, but still manageable on change.



The true power of good O-O (in this context) comes of separation of

interface and implementation, so you CAN change the interface and match

the clients and library to match the new interface, without worrying (too

much) you missed some detail. And if it does not work, debugging is

easier, thanks to a clearly defined interface.



But re-usable libraries of O-O code are best left to the experts and

downloaded from boost.

I will take the point as far as conceding that reuse is not the primary benefit of the O-O approach.

All programs are finite state machines, the state being the value of all ofthe program's data memory. But for non-trivial programs, it's beyond the capacity of the human mind to deal with a program described as a finite state machine. Programming languages and techniques should enable humans to describe programs with minimal errors. An object cannot be put into an invalid state, so long as it's interface rules are followed. "Seeing" the correctness of the program state changes becomes easier, as the state is the concatenation of the states of a set of objects. (The size of the set is limited as much as possible by object containment hierarchies.) But this onlyworks if the correctness of the object implementation can be evaluated in isolation (from the program). I don't see how that would be the case, if the definition of the object's interface is mostly driven by the specifics of the program (or containing object).
 
W

woodbrian77

But re-usable libraries of O-O code are best left to the experts and
downloaded from boost.

I think some of Boost is good. However, I believe the
C++ Middleware Writer has a number of advantages over
the serialization library in Boost.


Brian
Ebenezer Enterprises - So far G-d has helped us.
http://webEbenezer.net
 
W

W Karas

Is 'std::pair' sole example? Then considering the size of standard

library it qualifies as "very rarely". Also it supports your point

that on such rare circumstances writing getters and setters is waste

of time.

It surprises me that the real and imaginary components are not public variables in the <complex> class template. Very unclear to me the value of making them private.
 
Ö

Öö Tiib

It surprises me that the real and imaginary components are not
public variables in the <complex> class template. Very unclear
to me the value of making them private.

It is nowhere said that 'std::complex<float>' must be implemented as
a class with two float members. The processor may have native support
for complex arithmetic and 'std::complex' may internally use it or
it may be is more efficient to implement it as array of two floats
internally for whatever reasons.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top