Board index » cppbuilder » Encapsulation question.

Encapsulation question.


2005-12-23 01:19:24 AM
cppbuilder64
I have a question for all you Gurus.
Im told to use Encapsulation when I code and this is the example I am given
...
How the heck does this have anything to do with hiding the implementation?
To me this is just extra path length in access to the data and does not
encapsulate anything. I abide by the KIS philosophy and this definition of
encapsulation tends to irk me. How about you? Am I wrong? Why not just
get rid of the __property and just put "TSqlParam FDRG_HERBAL;" in the
public section?
private:
TSqlParam FDRG_HERBAL;
public:
__property TSqlParam DRG_HERBAL = { read=FDRG_HERBAL,
write=FDRG_HERBAL };
 
 

Re:Encapsulation question.

"Larry Griffiths" < XXXX@XXXXX.COM >writes:
Quote
I have a question for all you Gurus.

Im told to use Encapsulation when I code and this is the example I am given
...
How the heck does this have anything to do with hiding the implementation?
To me this is just extra path length in access to the data and does not
encapsulate anything. I abide by the KIS philosophy and this definition of
encapsulation tends to irk me. How about you? Am I wrong? Why not just
get rid of the __property and just put "TSqlParam FDRG_HERBAL;" in the
public section?

private:

TSqlParam FDRG_HERBAL;

public:

__property TSqlParam DRG_HERBAL = { read=FDRG_HERBAL,
write=FDRG_HERBAL };
This definately is better encapsulated, even if it feels like more
work. However, how you approach the encapsulation can be open to
further consideration. For example, a __property is non-standard,
Borland-exclusive feature. It works well as designed, but unless you
have code that is intimately married to VCL, I don't suggest using
it. That is, there are other standard ways to accomplish the same
thing, that does not tie your code to proprietary extensions.
That is, of course, writing inline accessor functions.
class Foo
{
public:
TSqlParam const * herbal() const { return &FDRG_HERBAL; }
void set_herbal(TSqlParam p) { FDRG_HERBAL = p; }
private:
TSqlParam FDRG_HERBAL;
};
I very much dislike all uppercase names for anything other than
preprocessor macros, but that's your own decision.
The question that you're really asking is "why is this better than
making the data public". Whether you use inline questions or
properties, the same question applies.
Good question.
When you write a class the INTERFACE is the most important thing.
It's how your code works with the rest of the world, and quite often,
once you commit to an interface you cannot ever change it, without
breaking lots of code.
Therefore, you want to make it easy for you to change your code
without breaking your clients. For one, that means to create a stable
interface that does not commit you to the internal implementation.
If users must go through a functional interface to get data from you,
then your internal implementation can change, provided you modify your
accessor functions to continue to return the right value.
One contrived example that still illustrates this idea quite well, I
think, is the idea of a "line". There are different ways to represent
it.
struct Line // BAD
{
int x1, y1, x2, y2;
};
This is about as bad as it gets. The representation has public data,
but permanently ties you to implementing the line as a pair of
endpoints. However, what if you wanted to store the line as something
else, like a starting point, an angle, and a length?
struct Line
{
int x, y;
double angle;
double length;
};
Now your users are all going to fail, because they are unable to use
your Line object with their code, which expects to access x1, x2, y1,
and y2 directly.
So let's go back to the first example:
class Line // Good
{
public:
int x1() const { return x1; }
int y1() const { return y1; }
int x2() const { return x2; }
int y2() const { return y2; }
private:
int x1_, y1_, x2_, y2_;
};
Ignoring the "setters" for the moment, had you done the above, your
clients would all call the functions x1(), y1(), etc, to access the
values representing the endpoints.
Now, if you still have to implement your "point-angle-length"
representation, you can safely make the change without affecting anyone:
class Line // Good
{
public:
int x1() const { return x1; }
int y1() const { return y1; }
int x2() const { return /*calc_x2()*/; }
int y2() const { return /*calc_y2()*/; }
// old clients won't use these...
double angle() const { return angle; }
double length() const { return
private:
int x1_, y1_;
double angle_;
double length_;
};
Notice, we have to calculate the values of x2 and y2 based on our
internal representation, but our CALLERS do not need to know that.
Further, this also means that nobody outside our Line object can ever
directly touch our internal data. That is good, because now, if the
data ever goes into an invalid state, we only have to consider the
code inside the Line class as suspect. If the data is public, than
there is an infinite number of places to look that can potentially
change the values. (As soon as you say you've looked at "all" the
code, I can write yet another class that mucks with the values, etc.)
If we have to go through the Line interface, we now have a known path
to access the data. That means that we can validate the data before
allowing it to be changed. We can perform pre-tests and post-checks
to ensure that our internal state is not corrupted. It means that we
have a place to set a breakpoint if we want to know when this data
changes. It provides a place where we can implement a counter for the
number of times the data changes, and so on.
Without guarding access to the variables, you are committed to the
first implementation forever, you have no control over who changes the
data, and cannot easily determine when, if, who, or why the value ever
changes. (De{*word*81}s can help here with certain breakpoints on data
addresses, but that's still awkaward, in comparison.)
And if you never need to do any of the above, you've only wated about
20 seconds up-front to type in a line of code that has no runtime
overhead. If you never need it, well, no big loss. But if you ever
do, it can save you hours and hours, and avoid angry customers, etc.
--
Chris (TeamB);
 

Re:Encapsulation question.

Chris, Im sorry but maybe I am not getting my point across.
Let me give another example.
private:
bool FSimpleVariableType;
public:
__property bool SimpleVariableType
(read=FSimpleVariableType,write=FSimpleVariableType)
The __property uses read and write that point to the simple variable in the
private section.
There is NOTHING to stop me from reading or writing to the variable
FSimpleVariableType in the private section.
It is just as if it were a simple variable in the public section. The
INTERFACE is a simple variable type of bool.
If I were to say there was an IMPLEMENTATION here it would be that i can
perform the type of
Arithmetic, Logical, and Bitwise Operations as defined for simple variables.
This IMPLEMENTATION is determined
by the compiler and is not subject "Hiding" unless code exists behind the
INTERFACE where the
__property read and write access specifiers point to code. This is what
ENCAPSULATION and data hiding mean to me.
A read can be done and the code can decide to pass back twice the variables
value or shift it or whatever before it returns the data etc.
and the code can take what is passed to it and throw it away or decide to
shift it, double it, multiply it or whatever and
then write it to the variable in the private section.
I see neither "data hiding" nor "Encapsulation" in the example I have shown
above. These __property statements are merely being used as an interface to
pass information between classes.
 

{smallsort}

Re:Encapsulation question.

Larry Griffiths wrote:
Simple answer:
Quote
This is what ENCAPSULATION and data hiding mean to me.
Yes but you're expecting more from the C++ language than it has to
offer.
Nothing in the C++ language says anything about the code generated by a
compiler. As long as it produces the results the language says it
should (including failing to compile invalid code) the compiler can
generate anything it wants. Furthermore although the language provides
programmers with access control it does not claim to be machine level
protection.
class TSecretive
{
int iAmASecret;
public:
int notASecret;
int safer() { return iAmASecret };
};
void wibble()
{
TSecretive jooble;
jooble.iAmASecret=5; // Should fail of course.
int i=jooble.safer();
int iToo=jooble.notASecret;
};
The language specification of course states that the above won't
compile. It does not however say how the compiler should implement the
last two assignments. The compiler is quite free to generate a single
machine language assignment for both of them. IOW if you were to only
see the machine language or assembler output there is no reason to
expect to be able to determine which is accessing a private data member
and which is accessing a public member.
All this 'public, private, protected' stuff is just so much hot air as
far as the code generator is concerned. They exist to /deter/ us
writing bad code. They are not intended to guarantee that we can never
do something silly. They aren't even guaranteed to prevent programmers
from learning the innner secrets of classes.
In the specific cases you mention the language rules mean that you as a
programmer always have to type 'SimpleVariableType' when you want to
access that private data member. That's all the rules mean but by
enforcing that they are helping you.
If the class implementation is changed so that 'FSimpleVariableType'
ceases to exist (replaced by functions for instance) clients of the
class will continue to function correctly.
That is encapsulation as far as C++ takes it.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:Encapsulation question.

"Larry Griffiths" < XXXX@XXXXX.COM >writes:
Quote
Chris, Im sorry but maybe I am not getting my point across.

Let me give another example.

private:

bool FSimpleVariableType;

public:

__property bool SimpleVariableType
(read=FSimpleVariableType,write=FSimpleVariableType)




The __property uses read and write that point to the simple variable in the
private section.

There is NOTHING to stop me from reading or writing to the variable
FSimpleVariableType in the private section.
It is just as if it were a simple variable in the public section. The
INTERFACE is a simple variable type of bool.
No it isn't, because you can change your property to use getter/setter
functions, without changing your interface at all. So basically, if
you don't need to intercept the call, the property gives you the
OPTION of doing so in the future in a completely transparent way to
the caller.
Quote
I see neither "data hiding" nor "Encapsulation" in the example I have shown
above. These __property statements are merely being used as an interface to
pass information between classes.
Nobody is directly accessing the data, because it is private. Callers
access the property, which is inbetween the caller and the data.
For example, suppose you removed the private FSimpleVariableType from
the class because you need to store it in a database instead of
storing it in the class itself. Easy: remove the private data member,
then write a getter function that queries the database, and write a
setter function that updates the database, and change the property to
make use of those functions. CALLERS of your class do not change.
A property "looks" like public data, but it isn't.
--
Chris (TeamB);
 

Re:Encapsulation question.

"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
A property "looks" like public data, but it isn't.
But unfortunately it's effectively the same if you use
the construct:
__property bool SimpleVariableType
(read=FSimpleVariableType,write=FSimpleVariableType)
No? If you want it to be "protected" you can use
getter/setter functions here. But why not use getter/setter
idiom to begin with?
It's probably just me but I don't see a great benefit from
properties.
 

Re:Encapsulation question.

"Duane Hebert" < XXXX@XXXXX.COM >wrote:
Quote
It's probably just me but I don't see a great benefit from
properties.
They're useful for tools - for instance, VCL component property
manipulation in the form editor.
If you're not creating a component, I'd avoid properties.
Alan Bellingham
--
ACCU Conference 2006 - 19-22 April, Randolph Hotel, Oxford, UK
 

Re:Encapsulation question.

"Duane Hebert" < XXXX@XXXXX.COM >writes:
Quote
"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>A property "looks" like public data, but it isn't.

But unfortunately it's effectively the same if you use
the construct:

__property bool SimpleVariableType
(read=FSimpleVariableType,write=FSimpleVariableType)

No? If you want it to be "protected" you can use
getter/setter functions here. But why not use getter/setter
idiom to begin with?

It's probably just me but I don't see a great benefit from
properties.
The compiler is smart enough to direct-wire access to the property to
be implemented as direct access to the member data, yes.
I am not a big fan of properties either, mainly because they're
proprietary (I thus prefer inline functions), but inline functions and
properties both are better options than public data.
Don't overlook that the _appearence_ of a property being equivalent to
public data is only a nice facade--it is not reality. For with a
property, you can eliminate the underlying data that they're
accessing, rewrite the property to use getter/setter functions, and
code that uses the property STILL WORKS. Your class interface stays
the same, even if you completely change the internal representations
of the class.
But if you have public data and clients are accessing it, you are
handcuffed into that design, and cannot remove that data member from
your class--ever--because you'll break clients. That means that a
decision from today can stick for years, or it will be extremely
painful to change.
A property is an interface; it's not just public data. You can
implement the interface with direct access to an actual data member,
OR you can implement it as function calls that calculate or fetch the
value. The benefit is that the IMPLEMENTATION of the property is your
choice, and it can be changed through time, without affecting callers.
With public data, you have no such options, and your design is set in
stone from day 1.
--
Chris (TeamB);
 

Re:Encapsulation question.

"Chris Uzdavinis (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
With public data, you have no such options, and your design is set in
stone from day 1.
Oh I totally agree. We don't allow public data members as
part of our "coding standards". I was just saying that if you
have to use properties, instead of using the syntax the OP
showed, you could use getter/setter functions in the property
read/write stuff. If not, you end up with the same thing, except that
you could add the getter/setter later and it wouldn't affect any
calling code.
 

Re:Encapsulation question.

"Duane Hebert" < XXXX@XXXXX.COM >writes:
Quote
read/write stuff. If not, you end up with the same thing, except that
you could add the getter/setter later and it wouldn't affect any
calling code.
True, but that's a major benefit that shouldn't be easily dismissed.
--
Chris (TeamB);
 

Re:Encapsulation question.

Very Good explanation of how encapsulation works, Chris, but I have the
OPTION of adding the __property in the future and adding getter/setter code
in the future. I have a better chance of winning the lottery than the
__property has a chance of being converted to getter/setter funtions at a
future time in our projects.
Considering now that the __property is using read/write with the private
variable as the parameters instead of get/setter code and that the chances
of ever using getter/setter code in the future is practically non-existance,
then describe how encapsulation exists in a __property using read, write
pointing at a variable in the private section.
I also liked the comment that __property is a compiler extension and raises
portability issues but I have yet to be involved in any porting projects.
Heh, maybe I will win the lottery afterall!
Quote

No it isn't, because you can change your property to use getter/setter
functions, without changing your interface at all. So basically, if
you don't need to intercept the call, the property gives you the
OPTION of doing so in the future in a completely transparent way to
the caller.

 

Re:Encapsulation question.

"Larry Griffiths" < XXXX@XXXXX.COM >writes:
Quote
Very Good explanation of how encapsulation works, Chris, but I have the
OPTION of adding the __property in the future and adding getter/setter code
in the future. I have a better chance of winning the lottery than the
__property has a chance of being converted to getter/setter funtions at a
future time in our projects.
True enough, unless you happen to have pesky users that take advantage
of the fact that the public data is actually data... and take the
address of the variable, or create a pointer-to-member to it.
Once it's exposed as real data, you're permitting a little more than
just read/write, and if you have it properly encapsulated from the
beginning, you don't have to worry about these "extra curricular"
uses.
Quote
Considering now that the __property is using read/write with the private
variable as the parameters instead of get/setter code and that the chances
of ever using getter/setter code in the future is practically non-existance,
I don't know what environment you code in, and I won't pretend to, but
I'm frequently surprised by the requirements customers throw at us.
Things I thought would never change do. Hopefully you know what the
future holds for you well enough that if you bet on using public data
(because it is a gamble), you won't lose too much down the road.
Encapsulation costs very little up front, and it's like an insurance
policy that gives almost complete coverage for an up-front cost of a
few seconds worth of typing. To me, it's a no-brainer decision.
Quote
then describe how encapsulation exists in a __property using read, write
pointing at a variable in the private section.
I also liked the comment that __property is a compiler extension and raises
portability issues but I have yet to be involved in any porting projects.
Heh, maybe I will win the lottery afterall!
I've said several times that I'm not a big fan of properties, and
would prefer encapsulation with inline functions, but if you're going
to choose between public data and properties, then I woudl recommend
you choose properties. However, if you're going to choose between
public data, properties, and inline functions, I'd recommend you
choose inline functions--unless you must use properties due to VCL
requirements.
--
Chris (TeamB);
 

Re:Encapsulation question.

Ok Chris,
I became a "pesky user" and created the sample code shown below...
Tracing down to the instruction level in the CPU window shows that both
pointers are the same
and the code produced is the same whether I use the private variable or the
__property variable name.
That seems to prove that the compiler treats the __property exactly like it
was the actual private variable when using pointers in BCB version 5. Try
again. :)
//--------------------------------------------------------------------------------------
private:
long FSimpleVar;
public:
__property long SimpleVar = { read=FSimpleVar, write=FSimpleVar };
// some code ...
long* p1;
long* p2;
p1 = &SimpleVar;
p2 = &FSimpleVar;
*p1 = 123;
long a = SimpleVar;
*p2 = 456;
long b = FSimpleVar;
//--------------------------------------------------------------------------------------
Quote

True enough, unless you happen to have pesky users that take advantage
of the fact that the public data is actually data... and take the
address of the variable, or create a pointer-to-member to it.

Once it's exposed as real data, you're permitting a little more than
just read/write, and if you have it properly encapsulated from the
beginning, you don't have to worry about these "extra curricular"
uses.

 

Re:Encapsulation question.

"Larry Griffiths" < XXXX@XXXXX.COM >writes:
Quote
Ok Chris,

I became a "pesky user" and created the sample code shown below...
Tracing down to the instruction level in the CPU window shows that
both pointers are the same and the code produced is the same whether
I use the private variable or the __property variable name. That
seems to prove that the compiler treats the __property exactly like
it was the actual private variable when using pointers in BCB
version 5. Try again. :)
Ok, I'm convinced a property isn't as good as an inline function. :)
Perhaps I gave properties more credit than they deserves, and thought
they would work better than public data, but you have shown that they
don't, at least in the simple case. They're slightly better with
functions, but since the user can be affected by switching from
direct-wired access to functions, it's not as transparent as I thought.
I'm disappointed that the property does that, which highlights the
problem with language extensions: they are not analyzed nearly as
meticulously as the features that make it into the official language
itself. The C++ committee is very through and additionally, their new
features are open to public scrutiny as well.
I think that this is an example where the optimization of
direct-wiring breaks encapsulation too much, and can be harmful. It's
partly a problem that can be attributed to Delphi, which doesn't have
the same issues, and when they were porting that feature into C++, the
surprising interaction between it and existing C++ features was
overlooked (or perhaps considered yet still ignored.)
In summary, I no longer recommend properties at all, except for VCL
interaction, but still recommend inline functions for encapsulating
access to data. (Thanks for the discussion, I learned something out
of it.)
--
Chris (TeamB);
 

Re:Encapsulation question.

Larry Griffiths wrote:
Quote
I became a "pesky user" and created the sample code shown below...
Tracing down to the instruction level in the CPU window shows that
both pointers are the same
and the code produced is the same whether I use the private variable
or the __property variable name.
That seems to prove that the compiler treats the __property exactly
like it was the actual private variable when using pointers in BCB
version 5. Try again. :)
But still, say you write your code like this:
class TMyClass
{
private:
int FMyVar;
public
__property int MyVar = { read = FMyVar, write = FMyVar };
};
Ok, this is basically then same as this:
class TMyClass
{
public:
int MyVar;
};
Then someone comes along and uses your code like this:
void TheirMethod()
{
TMyClass mc;
mc.MyVar = 10;
}
Now, suppose you decide to make your code use a DB instead of the memory
storage for the value in MyVar. Now, if you use properties, all yon need to
do, is change your class to this:
class TMyClass
{
private:
void __fastcall SetMyVar( int Value );
int __fastcall GetMyVar( int Value );
public:
__property int MyVar = { read = GetMyVar, write = SetMyVar };
};
Any code that uses this class doesn't change a bit. But if you go with
public access to the actual int, well, makes a bit of a mess:
void TheirMethod()
{
// TMyClass mc;
// mc.MyVar = 10;
Db->Open( "mydb", "table" );
Db->FieldByName( "MyValue" )->AsInteger = 10;
}
Jonathan
jomitech.com/mtbcc32.shtml - Multi-threaded compilation for BCB
jomitech.com/forum - JomiTech Forums