Connecting Tech Pros Worldwide Forums | Help | Site Map

How to avoid repeating code?

shuisheng
Guest
 
Posts: n/a
#1: Sep 1 '06
Dear All,

Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?

class CA1
{
public:
void func1( );
void func2( );
...
};

class CA2
{
public:
void func1( );
void func2( );
...
};

class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}

I appreciate your help.

Shuisheng


shadowman615@comcast.net
Guest
 
Posts: n/a
#2: Sep 1 '06

re: How to avoid repeating code?


shuisheng wrote:
Quote:
Dear All,
>
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
>
class CA1
{
public:
void func1( );
void func2( );
...
};
>
class CA2
{
public:
void func1( );
void func2( );
...
};
>
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}
>
I suppose the simplest solution is to make class CA a virtual base
class, with CA1 and CA2 subclasses.

Then you could create a container of pointers to CA...

Without explaining the entire concept, my advice is to read up on
polymorphism for some examples of this.

Phlip
Guest
 
Posts: n/a
#3: Sep 1 '06

re: How to avoid repeating code?


shuisheng wrote:
Quote:
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
Make CA1 and CA2 public.

Your current plan only pretends they are private. Users of CA are aware of
them, so they are /de-facto/ public.
Quote:
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}
I am aware one of the first OO rules we learn is "don't make data members
public". Rules are meant to be made, followed, and broken. In this case, the
real rule behind that rule is "don't make primitive things globally
writable".

In your case, CA1 and CA2 are real objects, not primitive data variables.
Abusing them has less consequences.

If you simply must encapsulate, then write get() methods that return CA1
const & and CA2 const &.

Alternately, don't allow users of CA to even know of CA1 and CA2's
existence. CA should only accept high-level requests to do things, and it
should figure out for itself how to do them. Interfaces should tell, not
ask, CA to do its tasks.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Noah Roberts
Guest
 
Posts: n/a
#4: Sep 1 '06

re: How to avoid repeating code?



shuisheng wrote:
Quote:
Dear All,
>
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
>
class CA1
{
public:
void func1( );
void func2( );
...
};
>
class CA2
{
public:
void func1( );
void func2( );
...
};
>
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}
>
I appreciate your help.
Well, it looks like your class is a candidate for removal as it doesn't
seem to do anything but put two object together. On the other hand it
probably does more in ... so lets assume it has a purpose.

This is the best way to do what you want. You could return a1 and let
the client call the function but this creates a smell known as a middle
man or cascade calls. You can't then alter your class to do other
things when that call is needed. It creates rigidity.

Other alternative is inheritance, inheritance also creates dependencies
(more so in fact) so composition is a better choice when possible.
Unless you need to behave polymorphically you don't want to
inherit....don't inherit for the purposes of reuse.

Noah Roberts
Guest
 
Posts: n/a
#5: Sep 1 '06

re: How to avoid repeating code?



Phlip wrote:
Quote:
I am aware one of the first OO rules we learn is "don't make data members
public". Rules are meant to be made, followed, and broken. In this case, the
real rule behind that rule is "don't make primitive things globally
writable".
Seems you don't fully understand that rule or its purpose.
Quote:
>
In your case, CA1 and CA2 are real objects, not primitive data variables.
Abusing them has less consequences.
No, it doesn't. It has the same consequences. You cannot change CA so
that it uses different objects or removes one or both CA# objects from
its internals.
Quote:
>
If you simply must encapsulate, then write get() methods that return CA1
const & and CA2 const &.
This has the same consequence and is only slightly better than a public
member variable (at least with this you can remove the variable and
just return a newly constructed object...assuming that changes aren't
expected to affect CA).
Quote:
>
Alternately, don't allow users of CA to even know of CA1 and CA2's
existence.
Yes, remove the inappropriate intamacy if there is one.

Siam
Guest
 
Posts: n/a
#6: Sep 1 '06

re: How to avoid repeating code?


shuisheng wrote:
Quote:
Dear All,
>
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
>
class CA1
{
public:
void func1( );
void func2( );
...
};
>
class CA2
{
public:
void func1( );
void func2( );
...
};
>
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}
>
I appreciate your help.
>
Shuisheng
If you're not too concerned about the amount of repeated code compiled,
but are simply too lazy to retype the method delegations for every
function, you could use a macro like:

#define DELEGATE(member, function) void member ## _ ##
function(){member.function();}

Now you can replace the function definitions in your class declaration
with something like DELEGATE(a1, func1) for each function you want
delegated. You would call the function in the same way you would have
in your version [ a1_func1() ].

Siam

Phlip
Guest
 
Posts: n/a
#7: Sep 1 '06

re: How to avoid repeating code?


Noah Roberts wrote:
Quote:
Quote:
>I am aware one of the first OO rules we learn is "don't make data members
>public". Rules are meant to be made, followed, and broken. In this case,
>the
>real rule behind that rule is "don't make primitive things globally
>writable".
>
Seems you don't fully understand that rule or its purpose.
You have such a pleasant manner of posting! I look forward to
pair-programming with you some day...
Quote:
Quote:
>In your case, CA1 and CA2 are real objects, not primitive data variables.
>Abusing them has less consequences.
>
No, it doesn't. It has the same consequences. You cannot change CA so
that it uses different objects or removes one or both CA# objects from
its internals.
The original design had that problem, as I hinted above. Thanks for
explicating it.
Quote:
Quote:
>If you simply must encapsulate, then write get() methods that return CA1
>const & and CA2 const &.
>
This has the same consequence and is only slightly better than a public
member variable (at least with this you can remove the variable and
just return a newly constructed object...assuming that changes aren't
expected to affect CA).
Right.
Quote:
Quote:
>Alternately, don't allow users of CA to even know of CA1 and CA2's
>existence.
>
Yes, remove the inappropriate intamacy if there is one.
Another way to detect inappropriate intimacy - even of things we have
foolishly made private - is examining the distance between them. If a module
way over there reaches out and grabs a class here - a class not in the
interface of this module, then you have inappropriate intimacy anyway.

One fix is to simply bust your modules apart with dynalink interfaces, ORB
interfaces, or even a soft glue language. Then your modules are small and
incapable of exploiting the C++ linker to go where they are not wanted. And
then the trivial details of what's public and private matter less to each
module.

This topic is "Encapsulation is Hierarchical". Have you heard the term
before?

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Noah Roberts
Guest
 
Posts: n/a
#8: Sep 1 '06

re: How to avoid repeating code?



Phlip wrote:
Quote:
Noah Roberts wrote:
>
Quote:
Quote:
I am aware one of the first OO rules we learn is "don't make data members
public". Rules are meant to be made, followed, and broken. In this case,
the
real rule behind that rule is "don't make primitive things globally
writable".
Seems you don't fully understand that rule or its purpose.
>
You have such a pleasant manner of posting! I look forward to
pair-programming with you some day...
Well, you explained it incorrectly and then gave advice based on that
mistaken definition. There is no "rule behind the rule" that narrows
it to primitive members.

I think there are probably two sides to your little stab with the pair
programming thing.
Quote:
>
Quote:
Quote:
In your case, CA1 and CA2 are real objects, not primitive data variables.
Abusing them has less consequences.
No, it doesn't. It has the same consequences. You cannot change CA so
that it uses different objects or removes one or both CA# objects from
its internals.
>
The original design had that problem, as I hinted above. Thanks for
explicating it.
Yes, the original design had problems but that wasn't what my
explaination was about. My explaination was counter to your claim that
exposing member variables somehow has less concequences if those
variables are not primitive. That simply isn't the case.

Phlip
Guest
 
Posts: n/a
#9: Sep 1 '06

re: How to avoid repeating code?


Noah Roberts wrote:
Quote:
Well, you explained it incorrectly and then gave advice based on that
mistaken definition. There is no "rule behind the rule" that narrows
it to primitive members.
That argument is "appeal to authority". No peer-reviewed author you know of
has proposed such a rule.

I appreciate your attention to the entry-level guidelines of programming,
yet knowing their meaning is more important than such knee-jerk reactions to
violating them.

Oh, BTW, the programming author Ward Cunningham sez to relax the private
data rules.
Quote:
I think there are probably two sides to your little stab with the pair
programming thing.
That is indeed how the expression "I look forward to pairing with you on
that" is used. (According to several authors...)
Quote:
Yes, the original design had problems but that wasn't what my
explaination was about. My explaination was counter to your claim that
exposing member variables somehow has less concequences if those
variables are not primitive. That simply isn't the case.
They can fend for themselves. They cannot, for example, be driven into an
incorrect state, if _their_ members are private.

They might indeed be driven into a state that CA does not expect. Yet they
might also if they were private. And they might have a reference to the CA,
so they can inform it of their state.

So we are back to the Hollywood Principle again...

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Kaz Kylheku
Guest
 
Posts: n/a
#10: Sep 1 '06

re: How to avoid repeating code?


shuisheng wrote:
Quote:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
This isn't valid syntax. Try again.

Do you mean

void a1_func() { a1.func1(); }

?
Quote:
private:
CA1 a1;
CA2 a2;
...
}
Doh, why don't you just make these members public? Then the user of the
class can write:

a.a1.func();
a.a2.func();

This way you don't have to write any wrapper functions. After all, your
class CA is just an aggregate that holds a1 and a2, so why not open it
up.

The only thing you have accomplished with those wrappers is changing a
period to an underscore:

a.a1_func();

Since a1 and a2 are already class objects, they can use their own
private: specifiers to restrict access.

Daniel T.
Guest
 
Posts: n/a
#11: Sep 1 '06

re: How to avoid repeating code?


In article <1157124573.982057.248150@b28g2000cwb.googlegroups .com>,
"shuisheng" <shuisheng75@yahoo.comwrote:
Quote:
Dear All,
>
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
>
class CA1
{
public:
void func1( );
void func2( );
...
};
>
class CA2
{
public:
void func1( );
void func2( );
...
};
>
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
The above doesn't compile. I'm going to assume you meant (as others
assumed):
void a1_func1() { a1.funct1(); }
// &c.
Quote:
...
private:
CA1 a1;
CA2 a2;
...
}
>
I appreciate your help.
Are all of CA1 and CA2's member-functions simply getting passed through
like that? If no, then leave it, your code is fine. If yes then I have
to wonder what CA's purpose in life is?
Daniel T.
Guest
 
Posts: n/a
#12: Sep 1 '06

re: How to avoid repeating code?


In article <1157133083.401324.111490@74g2000cwt.googlegroups. com>,
"Kaz Kylheku" <kkylheku@gmail.comwrote:
Quote:
shuisheng wrote:
Quote:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
>
This isn't valid syntax. Try again.
>
Do you mean
>
void a1_func() { a1.func1(); }
>
?
>
Quote:
private:
CA1 a1;
CA2 a2;
...
}
>
Doh, why don't you just make these members public? Then the user of the
class can write:
>
a.a1.func();
a.a2.func();
>
This way you don't have to write any wrapper functions. After all, your
class CA is just an aggregate that holds a1 and a2, so why not open it
up.
>
The only thing you have accomplished with those wrappers is changing a
period to an underscore:
>
a.a1_func();
>
Since a1 and a2 are already class objects, they can use their own
private: specifiers to restrict access.
Your assuming that all functions of a1 and a2 should be available to
clients of CA and that may not be the case.
Phlip
Guest
 
Posts: n/a
#13: Sep 1 '06

re: How to avoid repeating code?


Daniel T. wrote:
Quote:
You're assuming that all functions of a1 and a2 should be available to
clients of CA and that may not be the case.
In that situation, CA1 and CA2 can befriend CA, who then only accesses the
secret methods.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


shuisheng
Guest
 
Posts: n/a
#14: Sep 1 '06

re: How to avoid repeating code?


Just give an example.

Assume I have a device which has several critical points to define the
device's pose. Those points are movable, rotatable along an axis and so
on.

class CPoint
{
public:
void Move(double displacement[3]);
void Rotate(double angle, double axis[3]);
private:
double x, y, z;
}

class CDevice
{
private:
CPoint pt1, pt2, pt3;
}

So to control the device's critical points, I have to repeat writing
the Move and Rotate operations on every critical point???

Daniel T.
Guest
 
Posts: n/a
#15: Sep 1 '06

re: How to avoid repeating code?


In article <vF%Jg.23064$gY6.4425@newssvr11.news.prodigy.com >,
"Phlip" <phlipcpp@yahoo.comwrote:
Quote:
Daniel T. wrote:
>
Quote:
You're assuming that all functions of a1 and a2 should be available to
clients of CA and that may not be the case.
>
In that situation, CA1 and CA2 can befriend CA, who then only accesses the
secret methods.
Now you are assuming that only CA should be allowed to call those
methods in all situations. That may not be the case either.

If CA's job is to maintain some invariant between its a1 and a2
variables, then it wouldn't make sense to make member-functions of CA1
and CA2 private, because they would only be private in the CA context
but not other contexts.
Phlip
Guest
 
Posts: n/a
#16: Sep 1 '06

re: How to avoid repeating code?


shuisheng wrote:
Quote:
Assume I have a device which has several critical points to define the
device's pose. Those points are movable, rotatable along an axis and so
on.
>
class CPoint
{
public:
void Move(double displacement[3]);
void Rotate(double angle, double axis[3]);
private:
double x, y, z;
}
>
class CDevice
{
private:
CPoint pt1, pt2, pt3;
}
>
So to control the device's critical points, I have to repeat writing
the Move and Rotate operations on every critical point???
I imagine this problem resembles an arm, like the "robotic" arm on the Space
Shuttle.

Here is a deliberately naive test case:

TEST(reach)
{
Point reachTo(42,10,1);
CDevice aDevice;
aDevice.reach(reachTo);
assert(Point(3,2,0.4) == aDevice.getPoint1());
assert(Point(6,5,0.7) == aDevice.getPoint2());
assert(Point(41,9,0.9) == aDevice.getPoint1());
}

I am guessing that pt1, pt2, and pt3 represent the shoulder, elbow, and
wrist of this robotic arm. (I'm aware that might not be what you mean. This
is just an example.)

Download UnitTest++, and use it to write tests like that, to simplify your
development.

My test shows that I don't tell the device How to reach to the point
[42,10,1]. I only tell the device Reach!, and where to reach to.

The device itself positions its own shoulder, elbow, and wrist such that the
hand at the end is at the point requested.

I am using this test case only as a design technique; as a way to consider
what I want the interface to do, in terms of its clients. If I know that
clients of this device only need to know the Reach point, then I can specify
the interface, simply, like this. pt1, pt2, and pt3 need only expose their
Move() operations to the Device, not to the whole world. Encapsulation is
hierarchical.

So the question for you: What do the clients of your device need it to do?
How do they need it to appear, to them? What do they look like, what do they
know, and what's the simplest interface on Device that will satisfy them?

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Phlip
Guest
 
Posts: n/a
#17: Sep 1 '06

re: How to avoid repeating code?


Daniel T. wrote:
Quote:
Now you are assuming that only CA should be allowed to call those
methods in all situations. That may not be the case either.
>
If CA's job is to maintain some invariant between its a1 and a2
variables, then it wouldn't make sense to make member-functions of CA1
and CA2 private, because they would only be private in the CA context
but not other contexts.
The goal, in general, is to give the entire capsule around CA, CA1, and CA2
the smallest surface area possible. Sometimes friendship can help with that.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Daniel T.
Guest
 
Posts: n/a
#18: Sep 1 '06

re: How to avoid repeating code?


In article <S_0Kg.7402$q63.4289@newssvr13.news.prodigy.com> ,
"Phlip" <phlipcpp@yahoo.comwrote:
Quote:
Daniel T. wrote:
>
Quote:
Now you are assuming that only CA should be allowed to call those
methods in all situations. That may not be the case either.

If CA's job is to maintain some invariant between its a1 and a2
variables, then it wouldn't make sense to make member-functions of CA1
and CA2 private, because they would only be private in the CA context
but not other contexts.
>
The goal, in general, is to give the entire capsule around CA, CA1, and CA2
the smallest surface area possible. Sometimes friendship can help with that.
Agreed, but you are assuming that CA1 and CA2 some kind of internal
utility classes that only CA uses. What if they are 'vector' and 'list'?
Phlip
Guest
 
Posts: n/a
#19: Sep 1 '06

re: How to avoid repeating code?


Daniel T. wrote:
Quote:
Agreed, but you are assuming that CA1 and CA2 some kind of internal
utility classes that only CA uses. What if they are 'vector' and 'list'?
My goodness, Danny, then they shouldn't befriend CA! Among other reasons,
they have closed source!

However, if they were vector and list, then CA should not expose them, not
even by an accessor to a constant reference. 3rd party classes have
super-wide interfaces, and we want to narrow the interfaces around the
region of CA, right?

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Daniel T.
Guest
 
Posts: n/a
#20: Sep 1 '06

re: How to avoid repeating code?


In article <1157141701.721555.201420@e3g2000cwe.googlegroups. com>,
"shuisheng" <shuisheng75@yahoo.comwrote:
Quote:
Just give an example.
>
Assume I have a device which has several critical points to define the
device's pose. Those points are movable, rotatable along an axis and so
on.
>
class CPoint
{
public:
void Move(double displacement[3]);
void Rotate(double angle, double axis[3]);
private:
double x, y, z;
}
>
class CDevice
{
private:
CPoint pt1, pt2, pt3;
}
>
So to control the device's critical points, I have to repeat writing
the Move and Rotate operations on every critical point???
No. The Device is supposed to control its own critical points. Move and
Rotate shouldn't be accessible to CDevice's clients at all.

Presumably CDevice has some invariants between pt1, pt2 and pt3 (if it
doesn't, then I have to wonder why it exists.) For example "distance(
pt1, pt2 ) - 23.0 < sigma". Obviously, if this is true, it would be
dangerous to allow clients of CDevice access to those points.

BTW, this is a *great* example. It shows exactly why other peoples
suggestion of making the contained objects public is a bad idea.
Phlip
Guest
 
Posts: n/a
#21: Sep 1 '06

re: How to avoid repeating code?


Daniel T. wrote:
Quote:
BTW, this is a *great* example. It shows exactly why other peoples
suggestion of making the contained objects public is a bad idea.
Sometimes, the design you suggested is bad too. That's why we are engineers;
to make tradeoffs, and find the sweet spots between the bad things.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Noah Roberts
Guest
 
Posts: n/a
#22: Sep 1 '06

re: How to avoid repeating code?



Phlip wrote:
Quote:
Noah Roberts wrote:
>
Quote:
Well, you explained it incorrectly and then gave advice based on that
mistaken definition. There is no "rule behind the rule" that narrows
it to primitive members.
>
That argument is "appeal to authority". No peer-reviewed author you know of
has proposed such a rule.
That isn't an appeal to authority.

http://www.nizkor.org/features/falla...authority.html

Now, if you can show that there is a rule behind the rule then so be
it. The "rule" you are talking about is the concept of information
hiding:

http://en.wikipedia.org/wiki/Information_hiding

Now, since you have brought up logical fallacy, albeit wrongly, then
I'll assume you are aware that it is on you to show that such a "rule
behind the rule" indeed exists as it is your claim.
Quote:
I appreciate your attention to the entry-level guidelines of programming,
yet knowing their meaning is more important than such knee-jerk reactions to
violating them.
You seem to be assuming you are the one that has the correct meaning in
mind. I certainly have my doubts on that and that is in fact what this
whole conversation is about...so that makes this new argument of yours
circular.
Quote:
Oh, BTW, the programming author Ward Cunningham sez to relax the private
data rules.
That _is_ an appeal to authority. Thank you for the illustration.
Quote:
Quote:
I think there are probably two sides to your little stab with the pair
programming thing.
>
That is indeed how the expression "I look forward to pairing with you on
that" is used. (According to several authors...)
Well, maybe you understood my meaning, and maybe not.
Quote:
Quote:
Yes, the original design had problems but that wasn't what my
explaination was about. My explaination was counter to your claim that
exposing member variables somehow has less concequences if those
variables are not primitive. That simply isn't the case.
>
They can fend for themselves. They cannot, for example, be driven into an
incorrect state, if _their_ members are private.
If you say so, can you show it? What if I show you how they can be:

parent.child().~ChildClassName();
Quote:
They might indeed be driven into a state that CA does not expect.
Which means the concequences for exposing them are no less severe.

Yet they
Quote:
might also if they were private. And they might have a reference to the CA,
so they can inform it of their state.
>
So we are back to the Hollywood Principle again...
Such application is a stretch and I don't recall ever being there to
begin with.

Daniel T.
Guest
 
Posts: n/a
#23: Sep 2 '06

re: How to avoid repeating code?


In article <8c1Kg.7407$q63.412@newssvr13.news.prodigy.com>,
"Phlip" <phlipcpp@yahoo.comwrote:
Quote:
Daniel T. wrote:
>
Quote:
Agreed, but you are assuming that CA1 and CA2 some kind of internal
utility classes that only CA uses. What if they are 'vector' and 'list'?
>
My goodness, Danny, then they shouldn't befriend CA! Among other reasons,
they have closed source!
>
However, if they were vector and list, then CA should not expose them, not
even by an accessor to a constant reference. 3rd party classes have
super-wide interfaces, and we want to narrow the interfaces around the
region of CA, right?
Right. Which was my point.
Daniel T.
Guest
 
Posts: n/a
#24: Sep 2 '06

re: How to avoid repeating code?


In article <MH1Kg.415$MF1.6@newssvr25.news.prodigy.net>,
"Phlip" <phlipcpp@yahoo.comwrote:
Quote:
Daniel T. wrote:
>
Quote:
BTW, this is a *great* example. It shows exactly why other peoples
suggestion of making the contained objects public is a bad idea.
>
Sometimes...
Yes, thanks for that. I should have said, "... is sometimes a bad idea."
loop
Guest
 
Posts: n/a
#25: Sep 2 '06

re: How to avoid repeating code?


Daniel T. wrote:
Quote:
In article <MH1Kg.415$MF1.6@newssvr25.news.prodigy.net>,
"Phlip" <phlipcpp@yahoo.comwrote:
>
>
Quote:
>>Daniel T. wrote:
>>
>>
Quote:
>>>BTW, this is a *great* example. It shows exactly why other peoples
>>>suggestion of making the contained objects public is a bad idea.
>>
>>Sometimes...
>
>
Yes, thanks for that. I should have said, "... is sometimes a bad idea."
true, my professor Dr. Robert once said so too :-D
Dawei Mark Gay
Stuart Golodetz
Guest
 
Posts: n/a
#26: Sep 2 '06

re: How to avoid repeating code?


"Phlip" <phlipcpp@yahoo.comwrote in message
news:P1_Jg.20119$kO3.7365@newssvr12.news.prodigy.c om...
<snip>
Quote:
I appreciate your attention to the entry-level guidelines of programming,
yet knowing their meaning is more important than such knee-jerk reactions
to violating them.
Of course you're right that it's important to know why particular guidelines
exist. Similarly, you're right that there are times when it's best to break
them, for instance when not doing so would make the code substantially more
complicated for no reason. I'm not convinced, on the other hand, that
capriciously breaking them, on the basis of being beyond all that "newbie"
stuff, is such a good idea. In my experience (albeit limited) such an
approach usually comes back and bites you. I suspect (indeed I'd be
interested to find out one way or the other) that many of the best
programmers strongly adhere to guidelines and convention unless there is a
compelling reason to do otherwise. It's surprising how often you find that
an "avant garde" approach to a problem is just one of many wrong approaches.
YMMV.

Regards,
Stu

<snip>


Phlip
Guest
 
Posts: n/a
#27: Sep 2 '06

re: How to avoid repeating code?


Stuart Golodetz wrote:
Quote:
It's surprising how often you find that an "avant garde" approach to a
problem is just one of many wrong approaches. YMMV.
One thing TDD users often discover is much of the static type checking they
formerly relied on now just gets in the way.

And I didn't advise to capriciously make private variables public; I advised
that if private members are themselves encapsulated objects, then making
them public is lower risk.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Stuart Golodetz
Guest
 
Posts: n/a
#28: Sep 2 '06

re: How to avoid repeating code?


"Phlip" <phlipcpp@yahoo.comwrote in message
news:1TfKg.13885$%j7.3782@newssvr29.news.prodigy.n et...
Quote:
Stuart Golodetz wrote:
>
Quote:
>It's surprising how often you find that an "avant garde" approach to a
>problem is just one of many wrong approaches. YMMV.
>
One thing TDD users often discover is much of the static type checking
they formerly relied on now just gets in the way.
Fair enough :) I find both testing and static type checking to be quite
useful, but everyone's got their own way of doing things.
Quote:
And I didn't advise to capriciously make private variables public; I
advised that if private members are themselves encapsulated objects, then
making them public is lower risk.
Yes, I realised. I think I was being a little bit pompous before, sorry! :)
That aside, though, I'm not sure I agree with you on this one. The purpose
of making things private is as much to keep the containing object in a
consistent state as it is to keep the contained objects in such a state.
Making them public may not allow the client to mess up the contained object,
but they may be able to modify it in such a way that the container is no
longer in a consistent state. This isn't a good thing, on the whole. Of
course, if the container is an aggregate, it's less of an issue.

Cheers,
Stu
Quote:
--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!

Jerry Coffin
Guest
 
Posts: n/a
#29: Sep 2 '06

re: How to avoid repeating code?


In article <1TfKg.13885$%j7.3782@newssvr29.news.prodigy.net >,
phlipcpp@yahoo.com says...

[ ... ]
Quote:
And I didn't advise to capriciously make private variables public; I advised
that if private members are themselves encapsulated objects, then making
them public is lower risk.
What it really comes down to is this: public vs. private isn't really
the issue. The real issue is one of maintaining control over the values
that are assigned to the variable in question. When you're dealing with
something like a raw int, the only way to keep any control over it is to
make it private and put that control into the accessor functions. When
you're dealing with something that already provides suitable control,
you rarely gain much by using accessors to impose the control
externally.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Phlip
Guest
 
Posts: n/a
#30: Sep 2 '06

re: How to avoid repeating code?


Stuart Golodetz wrote:
Quote:
That aside, though, I'm not sure I agree with you on this one. The purpose
of making things private is as much to keep the containing object in a
consistent state as it is to keep the contained objects in such a state.
That's the primary syntactic reason.

The primary semantic reason is to help us design client objects that know
nothing about these variables, even their existences.
Quote:
Making them public may not allow the client to mess up the contained
object, but they may be able to modify it in such a way that the container
is no longer in a consistent state. This isn't a good thing, on the whole.
Even if they are private, their state might derail. Static typechecking is
only a secondary defensive measure.

Test cases and higher-level modularization are primary defensive measures.
Quote:
Of course, if the container is an aggregate, it's less of an issue.
Huh? You mean that, given std::list<foo>, the list can't grab the foo's
privates? That can't be what you mean! (And I know list ain't an
aggregate...)

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Stuart Golodetz
Guest
 
Posts: n/a
#31: Sep 2 '06

re: How to avoid repeating code?


"Phlip" <phlipcpp@yahoo.comwrote in message
news:AHlKg.14032$%j7.7093@newssvr29.news.prodigy.n et...
Quote:
Stuart Golodetz wrote:
>
Quote:
>That aside, though, I'm not sure I agree with you on this one. The
>purpose of making things private is as much to keep the containing object
>in a consistent state as it is to keep the contained objects in such a
>state.
>
That's the primary syntactic reason.
>
The primary semantic reason is to help us design client objects that know
nothing about these variables, even their existences.
Yes, that's certainly true. (I wasn't intending to enumerate all the (many)
good reasons for making things private. My comment was a relative one.)
Quote:
Quote:
>Making them public may not allow the client to mess up the contained
>object, but they may be able to modify it in such a way that the
>container is no longer in a consistent state. This isn't a good thing, on
>the whole.
>
Even if they are private, their state might derail. Static typechecking is
only a secondary defensive measure.
That's also true. Why "typechecking" rather than access-checking out of
interest? The two things seem to be distinct.
Quote:
Test cases and higher-level modularization are primary defensive measures.
>
Quote:
>Of course, if the container is an aggregate, it's less of an issue.
>
Huh? You mean that, given std::list<foo>, the list can't grab the foo's
privates? That can't be what you mean! (And I know list ain't an
aggregate...)
No, that wasn't what I meant. What I meant was things like:

struct Point
{
int x, y;
};

for instance, as opposed to:

class Point
{
private:
int x, y;
public:
int get_x() const { return x; }
// etc. (includes all manner of things which would make the class
actually usable)
};

In cases like this, where it's ok to modify the internal state of a Point,
it's not such a problem. There is a case to be made for Point objects being
immutable here, actually, but that's another matter. By immutable, I mean
lacking in mutators and having instead methods like, say:

Point translate(int dx, int dy) { return Point(x+dx,y+dy); }

etc.

I'm not sure I subscribe to that point of view entirely, but that's another
matter.

Regarding your somewhat humorous list example, I'm not actually sure what
you're getting at, could you explain? I'm both amused and bemused at once :)

Cheers,
Stu
Quote:
--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!

Stuart Golodetz
Guest
 
Posts: n/a
#32: Sep 2 '06

re: How to avoid repeating code?


"Jerry Coffin" <jcoffin@taeus.comwrote in message
news:MPG.1f638c73d368ad798971e@news.sunsite.dk...
Quote:
In article <1TfKg.13885$%j7.3782@newssvr29.news.prodigy.net >,
phlipcpp@yahoo.com says...
>
[ ... ]
>
Quote:
>And I didn't advise to capriciously make private variables public; I
>advised
>that if private members are themselves encapsulated objects, then making
>them public is lower risk.
>
What it really comes down to is this: public vs. private isn't really
the issue. The real issue is one of maintaining control over the values
that are assigned to the variable in question. When you're dealing with
something like a raw int, the only way to keep any control over it is to
make it private and put that control into the accessor functions. When
you're dealing with something that already provides suitable control,
you rarely gain much by using accessors to impose the control
externally.
It's worth observing, though, that which values that can be assigned to the
variable in question often depends on the containing object. If that's not
the case in a particular instance, then so be it, but if it is then you
would be unwise to make the variable public. The key phrase in what you were
saying is "something that already provides suitable control" - a class
doesn't know what other class might contain an instance of it, so it
literally can't provide such suitable control. Only the containing class
knows the restrictions which need to be applied to the contained instance.

Regards,
Stu
Quote:
--
Later,
Jerry.
>
The universe is a figment of its own imagination.

Stuart Golodetz
Guest
 
Posts: n/a
#33: Sep 2 '06

re: How to avoid repeating code?


"Jerry Coffin" <jcoffin@taeus.comwrote in message
news:MPG.1f638c73d368ad798971e@news.sunsite.dk...
Quote:
In article <1TfKg.13885$%j7.3782@newssvr29.news.prodigy.net >,
phlipcpp@yahoo.com says...
>
[ ... ]
>
Quote:
>And I didn't advise to capriciously make private variables public; I
>advised
>that if private members are themselves encapsulated objects, then making
>them public is lower risk.
>
What it really comes down to is this: public vs. private isn't really
the issue. The real issue is one of maintaining control over the values
that are assigned to the variable in question. When you're dealing with
something like a raw int, the only way to keep any control over it is to
make it private and put that control into the accessor functions. When
you're dealing with something that already provides suitable control,
you rarely gain much by using accessors to impose the control
externally.
>
--
Later,
Jerry.
>
The universe is a figment of its own imagination.
While I'm thinking about it, I think the key word which I've been missing
here is "invariants". Suppose we have the following situation:

class Y
{
//...
};

class X
{
//...
public:
Y y;
//...
};

(The comments in the above indicate (for our purposes, arbitrary) other
code, incidentally). Now, suppose both X and Y have datatype invariants
which all their methods studiously maintain. What I'm suggesting is that
uses of the y member of an instance of X may result in X's datatype
invariant being violated. It's theoretically possible that Y could be
written in such a way that it would ensure that X's invariant was
maintained, but that would make life very difficult for the author of Y, who
might not even know that X exists. Of course, it's not necessarily the case
that uses of y will cause X's invariant to be violated; that depends on what
X's invariant actually is and what the uses of y do. If, as in the Point
example I gave in my other post, there is no invariant, then maintaining
internal consistency is not a motive to make the member variables private.
(There may be other motives.)

A little disclaimer: Since both you and Phlip seem to agree on this, I have
to wonder whether I'm talking rubbish here?! Sorry if I am; perhaps I'm
missing the point. If so, could you give a small, concrete example of what
you mean?

Regards,
Stu


Alf P. Steinbach
Guest
 
Posts: n/a
#34: Sep 3 '06

re: How to avoid repeating code?


* shuisheng:
Quote:
>
class CA1
{
public:
void func1( );
void func2( );
...
};
>
class CA2
{
public:
void func1( );
void func2( );
...
};
>
class CA
{
public:
void a1_func1( a1.func1( ) );
void a1_func2( a1.func2( ) );
...
void a2_func1( a2.func1( ) );
void a2_func2( a2.func2( ) );
...
private:
CA1 a1;
CA2 a2;
...
}
>
I appreciate your help.
You have not explained the purpose of class CA, which as it stands can
be entirely eliminated.

The discussion so far has assumed various scenarios, like (1) class CA
presents only a subset of CA1+CA2, or (2) class CA enforces some
relationship between members a1 and a2 (a class invariant). But I think
the most likely is (3) class CA really serves no useful purpose.

In that case, eliminate it.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jerry Coffin
Guest
 
Posts: n/a
#35: Sep 3 '06

re: How to avoid repeating code?


In article <DbadncImXZ2rl2fZnZ2dnUVZ8s6dnZ2d@pipex.net>,
sgolodetz@dNiOaSl.PpAiMpPeLxE.AcSoEm says...

[ ... ]
Quote:
It's worth observing, though, that which values that can be assigned to the
variable in question often depends on the containing object.
At least in my experience, it often depends on the containing _class_,
and less often on the actual containing object (i.e. the instance as
opposed to the class). That may easily be what you meant, but (at least
to me) it's a significant distinction.
Quote:
If that's not
the case in a particular instance, then so be it, but if it is then you
would be unwise to make the variable public. The key phrase in what you were
saying is "something that already provides suitable control" - a class
doesn't know what other class might contain an instance of it, so it
literally can't provide such suitable control. Only the containing class
knows the restrictions which need to be applied to the contained instance.
IME, at least 80% of the time, all that's really needed is fairly simple
range-checking. In this case, it's pretty easy to isolate the work into
one small, fairly simple class. (I've posted roughly similar code to
this previously, but this is slightly different from them -- this
supports floating point types, and finally gets around to fixing a
problem I introduced years ago, of throwing an exception upon attempting
to extract an out-of-range value, rather than setting the stream's fail
bit as it should).

#include <exception>
#include <iostream>
#include <functional>
#include <ios>

template <class T, class less=std::less<T
class bounded {
const T lower_, upper_;
T val_;

bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}

void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}

public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}

bounded(bounded const &init) { assign(init); }

bounded &operator=(T const &v) { assign(v); return *this; }

operator T() const { return val_; }

friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >temp;

if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};

Now, the parent class uses something like:

struct geoPosition {
bounded<doublelatitude(-90.0, 90.0);
bounded<doublelongitude(-180.0, 180.0);
// ...
};

The range is now directly documented in the definition, rather than
being spread throughout the code of the owning class. This code itself
is simple enough that testing and verification is trivial, and it
isolates the range checking, so changes in the owning class can't
accidentally by-pass the range-checking anywhere, or things like that.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Phlip
Guest
 
Posts: n/a
#36: Sep 3 '06

re: How to avoid repeating code?


Stuart Golodetz wrote:
Quote:
Quote:
>Even if they are private, their state might derail. Static typechecking
>is only a secondary defensive measure.
>
That's also true. Why "typechecking" rather than access-checking out of
interest? The two things seem to be distinct.
Their common aspect is they are a secondary defensive measure. Static
checking of a program source, at compile-time.
Quote:
...What I meant was things like:
>
struct Point
{
int x, y;
};
>
for instance, as opposed to:
>
class Point
{
private:
int x, y;
public:
int get_x() const { return x; }
// etc. (includes all manner of things which would make the class
actually usable)
};
>
In cases like this, where it's ok to modify the internal state of a Point,
it's not such a problem.
If the struct Point is itself private to a known capsule, such as a module
or package.
Quote:
Regarding your somewhat humorous list example, I'm not actually sure what
you're getting at, could you explain? I'm both amused and bemused at once
:)
My list<foo>? I forgot some engineers use "aggregate" to mean "dumb struct".

In generics, the container knows nothing about the contained, except its
primitive interface. ==, >, =, etc.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


Jerry Coffin
Guest
 
Posts: n/a
#37: Sep 3 '06

re: How to avoid repeating code?


In article <xredna7SzZv_k2fZRVnyig@pipex.net>,
sgolodetz@dNiOaSl.PpAiMpPeLxE.AcSoEm says...

[ ... ]
Quote:
While I'm thinking about it, I think the key word which I've been missing
here is "invariants". Suppose we have the following situation:
>
class Y
{
//...
};
>
class X
{
//...
public:
Y y;
//...
};
>
(The comments in the above indicate (for our purposes, arbitrary) other
code, incidentally). Now, suppose both X and Y have datatype invariants
which all their methods studiously maintain. What I'm suggesting is that
uses of the y member of an instance of X may result in X's datatype
invariant being violated.
The question in my mind at that point is whether Y is really the correct
data type to be using in X. If X needs to enforce constraints on y
beyond those inherent in Y, then it seems fairly likely to me that Y
really isn't the correct data type. The cure would be to create a class
(possibly a derivative of Y) that really is the correct data type, and
then use it.

There are situations that are a bit more difficult. The most obvious is
when/if you need to enforce a constraint that is based on a relationship
between two different objects. For example, consider a pair of X and Y
coordinates, but you're only allowed to create a position that's inside
of a particular country (or state, county, city, etc.) Since most of the
boundaries aren't going to be precise rectangles, the permissible values
of X and Y are interrelated, and you can't enforce either separately
from the other.

IME, this can still usually be handled by creating a suitable data type.
Range checking might become somewhat (or even extremely) complex --
perhaps requiring an extensive data structure representing a map to tell
whether a particular value is in bounds or not. Nonetheless, the idea
remains the same -- first, realizing that if two such pieces of data are
really so closely related, they should probably be represented as a
single value of some composite type, and second, creating a class
specifically to represent that type.
Quote:
A little disclaimer: Since both you and Phlip seem to agree on this, I have
to wonder whether I'm talking rubbish here?! Sorry if I am; perhaps I'm
missing the point. If so, could you give a small, concrete example of what
you mean?
I don't think you're talking rubbish; I think it's more a difference in
emphasis. As much as possible, I prefer to keep the requirements on any
one class small, simple, easily understood and easily articulated. IMO,
enforcing a set of constraints is a sufficient responsibility for a
class. In fact, under some circumstances, it's worth breaking it up into
two classes -- one class (similar to the one I posted yesterday) that
actually enforces the constraint, and a second policy class that's
passed as a parameter to the first that actually determines what's in or
out of bounds for the particular type in question.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Stuart Golodetz
Guest
 
Posts: n/a
#38: Sep 4 '06

re: How to avoid repeating code?


"Phlip" <phlipcpp@yahoo.comwrote in message
news:9FDKg.15030$%j7.6786@newssvr29.news.prodigy.n et...
Quote:
Stuart Golodetz wrote:
>
Quote:
Quote:
>>Even if they are private, their state might derail. Static typechecking
>>is only a secondary defensive measure.
>>
>That's also true. Why "typechecking" rather than access-checking out of
>interest? The two things seem to be distinct.
>
Their common aspect is they are a secondary defensive measure. Static
checking of a program source, at compile-time.
>
Quote:
>...What I meant was things like:
>>
>struct Point
>{
> int x, y;
>};
>>
>for instance, as opposed to:
>>
>class Point
>{
>private:
> int x, y;
>public:
> int get_x() const { return x; }
> // etc. (includes all manner of things which would make the class
>actually usable)
>};
>>
>In cases like this, where it's ok to modify the internal state of a
>Point, it's not such a problem.
>
If the struct Point is itself private to a known capsule, such as a module
or package.
Certainly if it's private I wouldn't worry too much about it. With something
as simple as Point, I'd be tempted to think that it wouldn't matter even if
it was public. Point itself doesn't have a datatype invariant, and if you
wrote it instead as a template, e.g.

template <typename T>
struct Point
{
T x, y;
};

then I can't think of any reason why the variables in it would ever change.
There's no real need to encapsulate with something like this. Well, perhaps
it could be argued both ways, I don't know.
Quote:
Quote:
>Regarding your somewhat humorous list example, I'm not actually sure what
>you're getting at, could you explain? I'm both amused and bemused at once
>:)
>
My list<foo>? I forgot some engineers use "aggregate" to mean "dumb
struct".
Engineer?! I'm a computer scientist! Oh, the shame of it... ;) (Just
kidding, incidentally.)
Quote:
In generics, the container knows nothing about the contained, except its
primitive interface. ==, >, =, etc.
True enough. Speaking of which, I still think it's a shame that you can't
really express constraints on contained types in C++. You can document
requirements, certainly, but if they're accidentally violated you usually
end up with a fairly obscure template error. Ah well.

Regards,
Stu
Quote:
--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!

Stuart Golodetz
Guest
 
Posts: n/a
#39: Sep 4 '06

re: How to avoid repeating code?


"Jerry Coffin" <jcoffin@taeus.comwrote in message
news:MPG.1f63d8c311d8a8f1989722@news.sunsite.dk...
Quote:
In article <DbadncImXZ2rl2fZnZ2dnUVZ8s6dnZ2d@pipex.net>,
sgolodetz@dNiOaSl.PpAiMpPeLxE.AcSoEm says...
>
[ ... ]
>
Quote:
>It's worth observing, though, that which values that can be assigned to
>the
>variable in question often depends on the containing object.
>
At least in my experience, it often depends on the containing _class_,
and less often on the actual containing object (i.e. the instance as
opposed to the class). That may easily be what you meant, but (at least
to me) it's a significant distinction.
I confess I didn't think too hard about it when I wrote it, but thinking
about it now I believe I actually did mean the containing object. Consider
this example (it may not be terribly good code, it's just for the purposes
of illustration):

class Rect
{
// DATATYPE INVARIANT: left <= right && top <= bottom

private:
int m_left, m_right, m_top, m_bottom;

void check_invariant(int left, int right, int top, int bottom)
{
if(left right || top bottom) throw ArbitraryException();
}

public:
void set_left(int left)
{
check_invariant(left, m_right, m_top, m_bottom);
m_left = left;
}

// etc.
};

In this case, the acceptable values for each of the private variables
depends on one of the other private variables. Thus what I can set m_left to
depends on the value of m_right in a given Rect instance. I can't enforce
this if m_left is public.
Quote:
Quote:
>If that's not
>the case in a particular instance, then so be it, but if it is then you
>would be unwise to make the variable public. The key phrase in what you
>were
>saying is "something that already provides suitable control" - a class
>doesn't know what other class might contain an instance of it, so it
>literally can't provide such suitable control. Only the containing class
>knows the restrictions which need to be applied to the contained
>instance.
>
IME, at least 80% of the time, all that's really needed is fairly simple
range-checking. In this case, it's pretty easy to isolate the work into
one small, fairly simple class. (I've posted roughly similar code to
this previously, but this is slightly different from them -- this
supports floating point types, and finally gets around to fixing a
problem I introduced years ago, of throwing an exception upon attempting
to extract an out-of-range value, rather than setting the stream's fail
bit as it should).
>
#include <exception>
#include <iostream>
#include <functional>
#include <ios>
>
template <class T, class less=std::less<T
class bounded {
const T lower_, upper_;
T val_;
>
bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}
>
void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}
>
public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}
>
bounded(bounded const &init) { assign(init); }
>
bounded &operator=(T const &v) { assign(v); return *this; }
>
operator T() const { return val_; }
>
friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >temp;
>
if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};
>
Now, the parent class uses something like:
>
struct geoPosition {
bounded<doublelatitude(-90.0, 90.0);
bounded<doublelongitude(-180.0, 180.0);
// ...
};
>
The range is now directly documented in the definition, rather than
being spread throughout the code of the owning class. This code itself
is simple enough that testing and verification is trivial, and it
isolates the range checking, so changes in the owning class can't
accidentally by-pass the range-checking anywhere, or things like that.
Well I like the above code :) I also think I can see how you could modify it
to take account of the situation I gave above. I'm going to give it a try
now, actually...

Cheers,
Stu
Quote:
--
Later,
Jerry.
>
The universe is a figment of its own imagination.

Stuart Golodetz
Guest
 
Posts: n/a
#40: Sep 4 '06

re: How to avoid repeating code?


"Stuart Golodetz" <sgolodetz@dNiOaSl.PpAiMpPeLxE.AcSoEmwrote in message
news:R_2dnWvH65OUpWHZnZ2dnUVZ8tGdnZ2d@pipex.net...
Quote:
"Jerry Coffin" <jcoffin@taeus.comwrote in message
news:MPG.1f63d8c311d8a8f1989722@news.sunsite.dk...
Quote:
>In article <DbadncImXZ2rl2fZnZ2dnUVZ8s6dnZ2d@pipex.net>,
>sgolodetz@dNiOaSl.PpAiMpPeLxE.AcSoEm says...
>>
>[ ... ]
>>
Quote:
>>It's worth observing, though, that which values that can be assigned to
>>the
>>variable in question often depends on the containing object.
>>
>At least in my experience, it often depends on the containing _class_,
>and less often on the actual containing object (i.e. the instance as
>opposed to the class). That may easily be what you meant, but (at least
>to me) it's a significant distinction.
>
I confess I didn't think too hard about it when I wrote it, but thinking
about it now I believe I actually did mean the containing object. Consider
this example (it may not be terribly good code, it's just for the purposes
of illustration):
>
class Rect
{
// DATATYPE INVARIANT: left <= right && top <= bottom
Oops, I clearly meant m_left <= m_right && m_top <= m_bottom. Never mind :)
Quote:
private:
int m_left, m_right, m_top, m_bottom;
<snip>
Quote:
Well I like the above code :) I also think I can see how you could modify
it to take account of the situation I gave above. I'm going to give it a
try now, actually...
>
Cheers,
Stu
Ok, my attempt looks something like the following. It's not as clear as it
could be, but it does work (I think!)

#include <istream>
#include <boost/shared_ptr.hpp>

template <typename T, typename CHECKER>
class Checked
{
private:
T m_t;
boost::shared_ptr<CHECKERm_checker;

void assign(const T& t)
{
if(check(t)) m_t = t;
else throw std::domain_error("Invalid assignment");
}

bool check(const T& t)
{
if(m_checker.get() != NULL) return m_checker->is_ok(t);
else return true;
}

public:
Checked(const T& t)
{
assign(t);
}

Checked& operator=(const T& rhs)
{
assign(rhs);
return *this;
}

operator const T&() const
{
return m_t;
}

friend std::istream& operator>>(std::istream& is, Checked& c)
{
T t;
is >t;
if(check(t)) m_t = t;
else is.setstate(std::ios::failbit);
return is;
}

void set_checker(CHECKER *pChecker)
{
m_checker.reset(pChecker);
if(check(m_t) == false) throw std::domain_error("Check violated");
}
};

template <typename T>
class LBoundChecker
{
private:
const T& m_lbound;
public:
LBoundChecker(const T& lbound)
: m_lbound(lbound)
{}

bool is_ok(const T& t)
{
return t >= m_lbound;
}
};

template <typename T>
class UBoundChecker
{
private:
const T& m_ubound;
public:
UBoundChecker(const T& ubound)
: m_ubound(ubound)
{}

bool is_ok(const T& t)
{
return t <= m_ubound;
}
};

struct SimpleTest
{
// DATATYPE INVARIANT: m_left <= m_right

Checked<int,UBoundChecker<int m_left;
Checked<int,LBoundChecker<int m_right;

SimpleTest() // establish the invariant arbitrarily
: m_left(0),
m_right(1)
{
m_left.set_checker(new UBoundChecker<int>(m_right));
m_right.set_checker(new LBoundChecker<int>(m_left));
}
};

I'm not sure I like all the set_checker() stuff, but otherwise problems
arise because I can't initialise both m_left and m_right at once. I think
your point that it can be done is made, though :) I'm sure it could be
implemented better with either more thought or a different programmer...

Regards,
Stu

<snip>


werasm
Guest
 
Posts: n/a
#41: Sep 4 '06

re: How to avoid repeating code?



shuisheng wrote:
Quote:
Dear All,
>
Assume there are three classes where CA has members of class CA1 and
CA2 as follows. To make the public functions of CA1 and CA2 can work on
the members a1 and a2 in a CA object, I just write all the functions
such as a1_func1(), a1_fun2(), a2_func1(), as_func2() in the CA
interface. I think this is a stupid way since if there are more
functions in CA1 and CA2, I need to repeat them all. Is there any good
way to implement it?
Simple solution would be to use the composite pattern (This looks like
it may be a candidate):

Example:
#include <vector//or list
#include <memory//for auto_ptr...

namespace nsa{
template <class DeleterT>
struct Deleter
{
void operator()( DeleterT*& lval )
{
delete lval;
lval = 0;
}
};

struct Leaf
{
virtual void f() = 0;
virtual ~Leaf(){ }
};

struct CA1 : public Leaf
{
void f(){ /* Some implementation */ }
};

class CA2 : public Leaf
{
void f(){ /* Some implementation */ }
};

class Composite //CA!!!
: public Leaf //Keep interface same
{
public:
typedef std::auto_ptr<std::vector<Leaf* LeaveT;

Composite( LeaveT leaves )
: leaves_( leaves.get() ?
leaves : LeaveT(new std::vector<Leaf*>) )
{
}

//void add( Leaf* ){ /*...*/ }
//void remove( Leaf* ){ /*...*/}

void f()
{
std::for_each( leaves_->begin(), leaves_->end(),
std::mem_fun( &Leaf::f ) );
}
~Composite()
{
std::for_each( leaves_->begin(), leaves_->end(), Deleter<Leaf>()
);
}
private:
LeaveT leaves_;
};

}//nsa

int main()
{
Composite::LeaveT leaves( new std::vector<Leaf*);
leaves->push_back( new CA1 );
leaves->push_back( new CA2 );
Composite ca( leaves );
ca.f(); //Calls CA1.f() and CA2.f()...
}

Quote:
I appreciate your help.
Hope it helps. For anybody who wants to know, the reason I'm using
auto_ptr is for ownership transferral, that leaves only require to be
created once. Some boost utility can be used to create the sequence
more elegantly than using push_backs.
Quote:
>
Shuisheng
OP ignore question below:

Anybody have a compile time solution? Using valuelists
(boost::inherit_linearly) perhaps. I would like to see?

Regards,

Werner

werasm
Guest
 
Posts: n/a
#42: Sep 4 '06

re: How to avoid repeating code?



Phlip wrote:
Quote:
shuisheng wrote:
>
Quote:
Make CA1 and CA2 public.
>
Your current plan only pretends they are private. Users of CA are aware of
them, so they are /de-facto/ public.
Hmmm, program for the future tense.
- Do we want to in future, always expose both CA1 and CA2's entire
interface, especially considering the fact that their interface may
consist of more than func1/func2 at a later stage (even though it is
narrow at present)?
- Would calling CA::a1_func1() in future, always imply that
CA1::func1() is actually called? Maybe in this trivial example, yes.
- What you are saying may be true if interfaces are extremely concise
(only contain one function), and will remain so indefinitely. Even
then, this makes the caller dependend on an interface other than the
interface he is working with currently. Following your (so much
referred to) principles (DIP), the caller won't even be exposed to the
interface of CA, so how would he be able to access members CA1 and CA2?
If using the less liked pimpl, however - well, hide the detail.

Quote:
In your case, CA1 and CA2 are real objects, not primitive data variables.
Abusing them has less consequences.
Disagree, one only wants to expose necessary interface. What about
interface that in future may become necessary. Abusing them (IMO) has
even more consequence.
Quote:
If you simply must encapsulate, then write get() methods that return CA1
const & and CA2 const &.
Do we want to expose the entire const interface, or make explicit that
which is necessary?
Quote:
Alternately, don't allow users of CA to even know of CA1 and CA2's
existence. CA should only accept high-level requests to do things, and it
should figure out for itself how to do them. Interfaces should tell, not
ask, CA to do its tasks.
Yes (the preferred choice), but not alternative to making them public.

Kind regards,

Werner

Phlip
Guest
 
Posts: n/a
#43: Sep 4 '06

re: How to avoid repeating code?


werasm wrote:
Quote:
Quote:
>In your case, CA1 and CA2 are real objects, not primitive data variables.
>Abusing them has less consequences.
>
Disagree, one only wants to expose necessary interface.
This aspect of the thread has been thoroughly discussed. I try not to
practice coding techniques that prevent future upgrades. Sometimes this
looks like a little slack in the coding style. It is not, and fixes could
easily include privatizing the two variables, then trivially fixing every
resulting syntax error.

Another form of Premature Optimization is premature publication. Don't
pretend you are writing a library that millions of user-programmers will
use, hence don't over-design your library such that no upgrade can ever
cause a global syntax error. Just wait till it happens (it might not), then
lean on the compiler, fix it, and keep going.

--
Phlip
http://c2.com/cgi/wiki?ZeekLand <-- NOT a blog!!!


werasm
Guest
 
Posts: n/a
#44: Sep 5 '06

re: How to avoid repeating code?



Phlip wrote:
Quote:
werasm wrote:
>
Quote:
Quote:
In your case, CA1 and CA2 are real objects, not primitive data variables.
Abusing them has less consequences.
Disagree, one only wants to expose necessary interface.
>
This aspect of the thread has been thoroughly discussed.
I thought I might have shed some new light on it :-). Maybe I was
wrong. I know you have lot of experience (read your stuff, or some of
it). I would rather teach the OP the principle of keeping data members
private than not (as opposed to you, I think). BTW (OT), I think in
some cases "Appeal to authority" can be a good thing. Especially when
one has to do something and you don't have the mental capability (due
to lack of experience, perhaps). Following good authorities mechanisms
often get you out of trouble at the outset. Later only, you understand
why. 80% of the time appeal to good authority can save ones bacon.
Often 80% is all you need to be homefree for ever :-...
Quote:
I try not to
practice coding techniques that prevent future upgrades. Sometimes this
looks like a little slack in the coding style. It is not, and fixes could
easily include privatizing the two variables, then trivially fixing every
resulting syntax error.
Not convincing. Unfortunately my compiler does not force me to make
that change (privatizing) when the interface of the classes whom I
aggregate (or use) change. If I use this rationale consistently in
large projects, it would just be a matter of time before things become
unmanageable. Rather "implement in terms of" and only expose the
necessary interface pertaining to the services I provide.
Quote:
>
Another form of Premature Optimization is premature publication. Don't
pretend you are writing a library that millions of user-programmers will
use, hence don't over-design your library such that no upgrade can ever
cause a global syntax error. Just wait till it happens (it might not), then
lean on the compiler, fix it, and keep going.
In this case, the problem is not that upgrades will cause a global
syntax error, but that upgrades won't cause a global syntax error and
that type A, containing type B, given that type A's state may be
affected by type B, may have its state influenced from externally (as
types B's interface is exposed). Then we also have the argument that
now client has to learn both A and Bs interface etc. I agree that
Premature Optimization (or the other form of it) should be avoided. One
has to discern though, between this and doing something right the first
time. You follow many principles I'm sure, that when looking sternly
upon them, one could consider them to be premature as well. It does not
prevent you from following them, as software does have the tendency to
change more often than less (as you of all people know). All in all you
do try and create hinge points prematurely at places which you
anticipate could change, don't you - ever?

If I follow one little principle consistently, which is...

Make datamembers private, and member functions private unless they
contribute to the functional interface.

.... I seem to have less problems (when I follow this principle) than
when I do not (IME). For this reason we will have to agree to disagree
:-).

Kind regards,

Werner

Noah Roberts
Guest
 
Posts: n/a
#45: Sep 5 '06

re: How to avoid repeating code?



Stuart Golodetz wrote:
Quote:
The purpose
of making things private is as much to keep the containing object in a
consistent state as it is to keep the contained objects in such a state.
In my opinion it is more about allowing change. Objects that expose
their internals create rigidity. You'll find it much more difficult to
alter a class if it's internals are open to everyone.

Closed Thread


Similar C / C++ bytes