From: Francis Glassborow on
Pat wrote:
> Francis Glassborow wrote:

>>
>> So start with:
>>
>> class Point {
>> public:
>> Point(double x = 0.0, double y = 0.0);
>> double x();
>> double y();
>> private:
>> double x_;
>> double y_;
>> };
>>
>> Later you can add (or replace the x_ and y_ with ) argument and
>> modulus data members and change the implementation of the public
>> access functions. Yes it can get quite complicated but the point is
>> that all the complexity is confined to the implementation of Point and
>> users of Point have no need to concern themselves with exactly how a
>> point is represented.
>>
>> And, yes, I know that there are some design issues particularly with
>> the constructors but the point I am trying to make is that public data
>> locks you into a particular representation of a point, but private
>> data maintains the abstraction (the concept of a point is independant
>> of the way we choose to identify it).
>>
>
> Thanks for the example. I probably will end up using a class because of
> the flexibility it allows with the public interface. I would like to be
> able to define point objects based on either cartesian or polar
> coordinates, and I think that would be easier to set up with a class. I
> do have one question though. Doesn't a structure also provide
> abstraction? For example, with overloaded operators I can write
> relations like,
>
> Point p3 = p1 + p2;
> Point p4 = 5*p1;
> ...
>
> which are independent of how the data is stored internally. So just like
> with a class, wouldn't this just require rewriting the function
> definitions to change the internal structure?

You seem to have got hooked on the idea that a struct and a class are
different in some important way, they aren't. The important thing is to
keep internal data internal and that is the concept of private access.
Apart from convention, you could just as well write the above as:

struct Point {
public:
Point(double x = 0.0, double y = 0.0);
double x();
double y();
private:
double x_;
double y_;
};
Indeed if you did that you could omit the first access specifier (the
'public:') but others would find your style non-idiomatic. The value of
idioms is that it makes it easier for others to understand you.
From: osmium on
"Francis Glassborow" wrote:

>The value of idioms is that it makes it easier for others to understand
>you.

Or, to make it almost impossible for an outsider to understand. In American
English we have:

Raining cats and dogs
Break a leg
Buy the farm

And on and on and on, like an *undocumented* sub-language, if you were not
raised up in the culture, you may never really get all these right..


From: Kaz Kylheku on
On 2009-12-07, Francis Glassborow <francis.glassborow(a)btinternet.com> wrote:
> So start with:
>
> class Point {
> public:
> Point(double x = 0.0, double y = 0.0);
> double x();
> double y();
> private:
> double x_;
> double y_;
> };

Just because you are accessing an x coordinate as ``obj.x'' rather
than ``obj.x()'' doesn't mean you are violating encapsulation.

This is a language issue.

With a suitable template, you can define members which look like
member variables, but actually do the work by means of getter and setter
functions, which can be targetted to do a polar<->rectangular
conversion.

Thus ``obj.x'' can actually perform a function call, and
``obj.x = value'' can perform a different function call.

And so there is no reason to worry about actual x and y data members
being accessed directly. You can represent your coordinate in the
straightforward way, with a public x and y that are ordinary numeric
data members. You can make them behave as abstract accessors later.

Kindly don't confuse newbies with shoddy computer science.
From: Francis Glassborow on
Kaz Kylheku wrote:
> On 2009-12-07, Francis Glassborow <francis.glassborow(a)btinternet.com> wrote:
>> So start with:
>>
>> class Point {
>> public:
>> Point(double x = 0.0, double y = 0.0);
>> double x();
>> double y();
>> private:
>> double x_;
>> double y_;
>> };
>
> Just because you are accessing an x coordinate as ``obj.x'' rather
> than ``obj.x()'' doesn't mean you are violating encapsulation.

But it sure as hell does in practice. Do not confuse theory with good
practice.

>
> This is a language issue.
Yes, C++ is not Lisp.

>
> With a suitable template, you can define members which look like
> member variables, but actually do the work by means of getter and setter
> functions, which can be targetted to do a polar<->rectangular
> conversion.

You clearly do not understand the issue.

>
> Thus ``obj.x'' can actually perform a function call, and
> ``obj.x = value'' can perform a different function call.

And that does not confuse the inexperienced? :}
>
> And so there is no reason to worry about actual x and y data members
> being accessed directly. You can represent your coordinate in the
> straightforward way, with a public x and y that are ordinary numeric
> data members. You can make them behave as abstract accessors later.

Much, much later. Indeed so much later that it is hardly ever done.
I have never seen your argument presented before which leads me to think
that it has no valid foundation.

The fact remains that with or without your approval, those being taught
C++ from scratch are taught (correctly IMNSHO) to make their data
members private.
From: Kaz Kylheku on
On 2009-12-09, Francis Glassborow <francis.glassborow(a)btinternet.com> wrote:
> The fact remains that with or without your approval, those being taught
> C++ from scratch are taught (correctly IMNSHO) to make their data
> members private.

Newbies being taught correctly are taught to make /everything/ private
that doesn't need to be, including most member functions. Not only
data members.

Your argument boils down to that things which are invoked without parentheses
are evil and should be made public, but whereas invoked with parentheses can be
made public.

If an object is understood to be a rectangular coordinate, and it has members
which are private, but there exist the public functions get_x() and get_y(),
then it actually does not truly have private members. These functions
almost directly expose the semantics of the object: that it has x and y
coordinates.

If the users of a coordinate class depend on the accessors get_x() and get_y(),
and if the users depend on the data members x and y, it is the same. In either
case, we have a dependency of the client code on a representational artifact of
the coordinate, which we cannot revoke without rewriting all of the client
code. In either case, we can still retarget and virtualize that class to use a
non-rectangular representation of the coordinate: we can make the data member
actually behave as an abstract accessor.

This can be done with existing features of C++.

At one point, it was the subject of a C++0x proposal: ``implicitly callable
functions''.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1611.pdf

How we can do this today is in various ways. E.g.

class myclass {
private:
void set_x(int);
int get_x();
public:
accessor<myclass, int> x;
myclass();
}

myclass::myclass()
: x(this, &myclass::set_x, &myclass::get_x)
{
}

Exercise for reader: implement accessor<>. The member x has to have an
assignment operator void operator =(int) which passes the value to
set_x, and a conversion operator from int which works by calling
get_x, and of course the constructor.

One nice thing is that we can even indirect upon x independently of the object
that it came from:

accessor<myclass, int> &a = obj.x;

a = 42; // calls obj.set_x(42)

You could teach newbies how to use all this, the same way that
you can teach newbies cout << foo << endl .