Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

are 'friend's really necessary ??

19 views
Skip to first unread message

Herman Moons

unread,
Mar 16, 1990, 11:23:52 AM3/16/90
to

I don't know whether this question appeared earlier on the net.
Are there any *good* reasons for having the friend concept in C++ ?

The example given in Lippman's book:

class Screen;

Screen myScreen;

cout << myScreen; // friend needed to implement this


does not seem convincing. The friend mechanism is used in this case to
circumvent a bad design choice. After all, << is an operator defined in
the stream classes, while outputting an object logically belongs to the
object itself (you say to the object: output yourself).
Wouldn't it be better to say:

class Screen {
ostream& operator>>= (ostream& out); // no friend needed here
};

myScreen >>= cout;
yourScreen >>= myScreen >>= cout;


Discussions with my colleagues didn't provide an example were friends were
really necessary. We could always find ways to implement our classes such
that the information hiding principle wasn't violated. We also couldn't
find a good example where data abstraction resulted in a serious loss of
efficiency (we could always find sensible inline functions that provided
fast access to the needed information).

So, if you have an example that really proves the necessity of the friend
mechanism, please post it. After all, if there is no real necessity, the
mechanism is just an unnessary loophole in the language to defeat the
information hiding principle.


-----------------------------------------------------------------------------
Herman Moons Katholieke Universiteit Leuven
Dept. of Computer Science
Tf : +32 (16) 20.06.56 Celestijnenlaan 200A
Fax: +32 (16) 20.53.08 B-3030 Heverlee-Leuven
Belgium
e-mail: her...@kulcs.uucp
her...@blekul60.bitnet
her...@cs.kuleuven.ac.be

-----------------------------------------------------------------------------

Hank Shiffman

unread,
Mar 17, 1990, 1:14:32 AM3/17/90
to
In article <1...@pollux.kulcs.uucp> her...@kulcs.UUCP () writes:
>
>I don't know whether this question appeared earlier on the net.
>Are there any *good* reasons for having the friend concept in C++ ?
>
>Discussions with my colleagues didn't provide an example were friends were
>really necessary. We could always find ways to implement our classes such
>that the information hiding principle wasn't violated. We also couldn't
>find a good example where data abstraction resulted in a serious loss of
>efficiency (we could always find sensible inline functions that provided
>fast access to the needed information).
>
>So, if you have an example that really proves the necessity of the friend
>mechanism, please post it. After all, if there is no real necessity, the
>mechanism is just an unnessary loophole in the language to defeat the
>information hiding principle.
>

One case where friend functions are appropriate is where we may get to
the function via typecasting. For example, let's say we implement a
ratio class. We have a constructor for a ratio which takes zero, one
or two integers. Now we want to implement subtraction. We might use
a member function:

ratio operator- (ratio&);

or a friend function:

friend ratio operator- (ratio&, ratio&);

We choose to implement using a member function. Now consider the
following piece of code:

main ()
{ ratio a(1,2), b, c;
b = a - 5;
c = 27 - b; }

When compiling "b = a - 5", C++ won't find a function which subtracts
an int from a ratio. However, there *is* a way to cast the int to a
ratio (the ratio constructor), so the operator- member function can do
the subtraction.

Now consider "c = 27 - b". We can't use the member function, since
C++ won't cast the recipient of the operator- "message". We *could*
recode this as "c = -b + 27", assuming that we've defined the unary
minus, but that's not fair to the user of our class.

If we implement operator- as a friend function, then C++ can cast
either one of the arguments to the ratio type and perform the
subtraction. The requirement that the target of the member function
be in the first position creates the need for friend functions.

BTW, Dewhurst & Stark's Programming In C++ has a good explanation of
this issue in relation to a complex number example.

Andrew Koenig

unread,
Mar 17, 1990, 9:25:57 AM3/17/90
to
In article <1...@pollux.kulcs.uucp>, her...@kulcs.uucp (Herman Moons) writes:

> I don't know whether this question appeared earlier on the net.
> Are there any *good* reasons for having the friend concept in C++ ?

Sure. One of the most common is when you're writing several
interrelated classes.

> The example given in Lippman's book:

> class Screen;

> Screen myScreen;

> cout << myScreen; // friend needed to implement this

> does not seem convincing. The friend mechanism is used in this case to
> circumvent a bad design choice.

It is at least as bad a design choice to require

myScreen >>= cout;

but to allow

cout << "hello world\n";

The inconsistent syntax does nothing to help program clarity.

I will admit, however that it is possible to write this particular
example without friends:

class MyScreen {
// ...
public:
ostream& print(ostream& o) {
// print *this on o
return o;
};
};

ostream& operator<<(ostream& o, const Screen& s) { return s.print(o); }

The operator<< defined here does not need to be a friend of MyScreen
as long as the print function is public.

Of course you may not want the print function to be public. After all,
there's no overriding reason to fix it as part of the interfact to
MyScreen. But if you make it private, then operator<< must be a
friend of MyScreen...
--
--Andrew Koenig
a...@europa.att.com

Dr. James Coggins

unread,
Mar 17, 1990, 5:22:44 PM3/17/90
to
In reply to the subject question, "No, but there are good reasons
for having them."

I don't like the friend examples where the reason for friend-ing
is to permit commutative usage of operators. That strikes me as
a syntactic cure for certain kinds of laziness, but on the other
hand, such cures can sure be useful.

A better example of friend classes arises in my COOL library where I have
two classes that are separated for the purpose of isolating some
highly changeable junk from the main class definition, which is pretty
clean and understandable. I make the classes friends and create
the junk class object in the constructor of the good class, providing
a pointer to the good object so the junk object knows what good object
it is associated with.

That's the only pair of friend classes in my library, and I have no
friend functions at all.

---------------------------------------------------------------------
Dr. James M. Coggins cog...@cs.unc.edu
Computer Science Department Questions: "How 'bout them HEELS?"
UNC-Chapel Hill Correct response:
Chapel Hill, NC 27599-3175 "How 'BOUT them Heels?"
and NASA Center of Excellence in Space Data and Information Science
---------------------------------------------------------------------

Ruud Harmsen

unread,
Mar 19, 1990, 9:07:25 AM3/19/90
to
In article <10...@alice.UUCP> a...@alice.UUCP (Andrew Koenig) writes:
>In article <1...@pollux.kulcs.uucp>, her...@kulcs.uucp (Herman Moons) writes:
>
>> I don't know whether this question appeared earlier on the net.
>> Are there any *good* reasons for having the friend concept in C++ ?
>
>Sure. One of the most common is when you're writing several
>interrelated classes.
>

Only too true. And isn't this also the fundamental weakness of the object
oriented concept? For in the real world, and so in any realistic
information system describing a part of that real world, *nearly all*
classes are interrelated to *nearly all* other classes. Classes often only
make sense just because of their relations to other classes.
So if you have to use friends for that, everyone will be anybody's friend,
and as a result of all this friendship, a *real* project in an OO-language
tends to become just the same mess as it does in a traditional language,
like C.

(Note: I admit I don't have experience with OOT, but only more so
with complicated applications).

Markku Sakkinen

unread,
Mar 20, 1990, 1:32:22 AM3/20/90
to
In article <10...@targon.UUCP> ru...@targon.UUCP (Ruud Harmsen) writes:
>In article <10...@alice.UUCP> a...@alice.UUCP (Andrew Koenig) writes:
>>In article <1...@pollux.kulcs.uucp>, her...@kulcs.uucp (Herman Moons) writes:
>>
>>> I don't know whether this question appeared earlier on the net.
>>> Are there any *good* reasons for having the friend concept in C++ ?
>>
>>Sure. One of the most common is when you're writing several
>>interrelated classes.
>>
>
>Only too true. And isn't this also the fundamental weakness of the object
>oriented concept? For in the real world, and so in any realistic
>information system describing a part of that real world, *nearly all*
>classes are interrelated to *nearly all* other classes. [...]
> ...

Here seems to be some misunderstanding - Koenig should probably have
written "_tightly_ interrelating". A given class need generally
be _directly_ interrelated only to relatively few other classes,
which we could call its acquaintances. In most cases, the communication
between acquaintances needs to use only public operations (and data).
Sometimes however, there is a real need for a closer cooperation
between some classes (without any inheritance relationship between them).
That's what friend declarations are good for.

Ada and Modula-2 have the advantage over almost all OO languages that
really tightly interrelated types can be defined within the same
package or module. Certainly both this facility and the friend concept
of C++ can be easily misused also.

Markku Sakkinen
Department of Computer Science
University of Jyvaskyla (a's with umlauts)
Seminaarinkatu 15
SF-40100 Jyvaskyla (umlauts again)
Finland
SAKK...@FINJYU.bitnet (alternative network address)

Rick Genter

unread,
Mar 20, 1990, 9:31:27 AM3/20/90
to
In article <10...@targon.UUCP> ru...@targon.UUCP (Ruud Harmsen) writes:

As one who does have experience with OOT and with complicated applications,
I (unfortunately) have to agree with the gist of this assessment.

There are classes of applications where OOT is wonderful. User interface is
one. Discrete simulation is another. But how about a globally-optimizing
incremental compiler? Or an operating system?

Actually, operating systems have potential; there are lots of "independent"
objects that have well defined behaviors (e.g., processes, threads, files,
users :-), but then there is all the other "cruft." Is a protocol an object?
If not, how does it fit in to an OO OS?

Note that these can be made to work, but at a significant performance penalty.
The penalty is not the penalty of a single virtual method invocation vs.
a single function call; I grant that that is (usually) insignficant. But
often what happens is that a method will invoke several other methods, each of
which will invoke other methods, and so on and so on. Suddenly that
insignificant overhead becomes quite significant.

It seems to me that a study needs to be performed not on how to make everything
OO, but on how to make composite designs work: i.e., how do I easily integrate
my OO UI with my procedural data-flow analysis.
- reg

mcco...@p.cs.uiuc.edu

unread,
Mar 22, 1990, 1:55:24 PM3/22/90
to

r...@ksr.UUCP says:
> There are classes of applications where OOT is wonderful. User interface is
> one. Discrete simulation is another. But how about a globally-optimizing
> incremental compiler? Or an operating system?

As it happens, the group I'm in is working on a globally optimizing
incremental compiler (for Smalltalk and written in Smalltalk). We
have class hierarchies representing various kinds of flow nodes,
register transfers, machine instructions, etc. OOT has served us
quite well in describing these objects.


Carl McConnell
Department of Computer Science
University of Illinois at Urbana-Champaign
INTERNET: mcco...@cs.uiuc.edu
UUCP: {uunet|convex|pur-ee}!uiucdcs!mcconnel
BITNET: mcconnel%cs.uiuc.edu@uiucvmd

Paul S. R. Chisholm

unread,
Mar 26, 1990, 10:56:32 PM3/26/90
to
(I tried to be careful about attribution; I apologize if I goofed.)

In article <1...@pollux.kulcs.uucp>, her...@kulcs.uucp (Herman Moons) writes:
> I don't know whether this question appeared earlier on the net.

(*sigh*) I don't suppose anyone's collecting frequently asked
questions (and their answers) . . . Also, please note that this whole
discussion deals only with the abstract data typing features of C++,
not the object-oriented features.

> Are there any *good* reasons for having the friend concept in C++ ?

In article <10...@alice.UUCP> a...@alice.UUCP (Andrew Koenig) writes:
> Sure. One of the most common is when you're writing several
> interrelated classes.

In article <10...@targon.UUCP>, ru...@targon.UUCP (Ruud Harmsen) writes:
> Only too true. And isn't this also the fundamental weakness of the
> object oriented concept? For in the real world, and so in any
> realistic information system describing a part of that real world,
> *nearly all* classes are interrelated to *nearly all* other
> classes. Classes often only make sense just because of their
> relations to other classes. So if you have to use friends for that,
> everyone will be anybody's friend, and as a result of all this
> friendship, a *real* project in an OO-language tends to become just
> the same mess as it does in a traditional language, like C.

As Dr. Koenig pointed out in a later article, "interrelated" means "the
implementation of one thing depends on the *implementation* of another
thing".

A "thing" in this case may be a whole class. If you're careful, only a
few functions in class B (e.g., member function foo and static member
function bar) will need to know about the implementation of class A; in
which case, only B::foo and B::bar will need be friends of A. This is
a Good Thing; it specifically limits what software can mess with an A,
and what code must be looked at when the implementation of A changes.

There's still a limitation, in that B::foo and B::bar must be visible
to A to be friends of A. That implies that one class's private
functions can only be friends of another class if the functions are
public (or possibly protected), or if the whole first class is a friend
of the second class. (I *assume* the visibility rules apply to
friendship.)

In article <6...@ksr.UUCP>, r...@ksr.UUCP (Rick Genter) writes:
> As one who does have experience with OOT and with complicated
> applications, I (unfortunately) have to agree with the gist of this

> assessment. . . .

> Note that these [hard applications] can be made to work, but at a


> significant performance penalty. The penalty is not the penalty of
> a single virtual method invocation vs. a single function call; I
> grant that that is (usually) insignficant. But often what happens
> is that a method will invoke several other methods, each of which
> will invoke other methods, and so on and so on. Suddenly that
> insignificant overhead becomes quite significant.

This has nothing to do with object-oriented design or programming; it
has to do with data abstraction, and with structuring software into
layers. (I assume that you're talking about function call overhead per
se, and not function invocation vs. virutual method invocation. The
difference is still trivial, especially if you add in the comparisons
that would otherwise need to be made.) Granted, almost all object-
oriented designs will have layering; but so will almost all non-trivial
designs, OO or otherwise.

One of the highlights of C++ is that it allows trivial layers to have
trivial cost (i.e., a layer that just invokes another layer can be
implemented with an inline function).

> It seems to me that a study needs to be performed not on how to make
> everything OO, but on how to make composite designs work: i.e., how
> do I easily integrate my OO UI with my procedural data-flow
> analysis.

What, ho! "Composite design" is a collection of guidelines to follow
when designing software: to maximize the strength (or "cohesion") of
modules, and to minimize the coupling between modules. These
principles are as applicable to OOD as any other design approach, and I
strongly recommend all of the following references:

L. L. Constantine, G. J. Meyers, and W. P. Stevens, "Structured
Design", IBM SYTEMS JOURNAL, vol. 13, no. 2, pp. 115-139.

Glenford J. Myers, RELIABLE SOFTWARE THROUGH COMPOSITE DESIGN, New
York: Petrocelli/Charter, 1975.

Edward Yourdon and Larry L. Constantine, STRUCTURED DESIGN:
FUNDAMENTALS OF A DISCIPLINE OF COMPUTER PROGRAM AND SYSTEMS DESIGN,
Englewood Cliffs, N.J.: Prentice-Hall, 1979.

The last is in some sense the most complete. It also describes what
has since been known as "structured design", or the Yourdon half of the
Yourdon/DeMarco methodology that underlies almost all CASE tools. One
starts by drawing dataflow diagrams; then one picks the "central
transform" in the diagram, making that the root of a tree, and
mechanically transforming the diagram into a tree. (The result,
according to a comment from my CASE instructor, does *not* produce
designs that have high cohesion and low coupling; but I have no
reference other than this heresay.)

While the method sounds reasonable, I've never been able to
non-trivially decompose an interactive application into a dataflow
diagram. Thus, Rick's comment about dataflow diagrams and OO user
interfaces baffles me.

Paul S. R. Chisholm, AT&T Bell Laboratories
att!pegasus!psrc, ps...@pegasus.att.com, AT&T Mail !psrchisholm
I'm not speaking for the company, I'm just speaking my mind.

edward.n.schiebel

unread,
Mar 27, 1990, 7:41:06 AM3/27/90
to
From article <45...@pegasus.ATT.COM>, by ps...@pegasus.ATT.COM (Paul S. R. Chisholm):

> A "thing" in this case may be a whole class. If you're careful, only a
> few functions in class B (e.g., member function foo and static member
> function bar) will need to know about the implementation of class A; in
> which case, only B::foo and B::bar will need be friends of A. This is
> a Good Thing; it specifically limits what software can mess with an A,
> and what code must be looked at when the implementation of A changes.
>
> There's still a limitation, in that B::foo and B::bar must be visible
> to A to be friends of A. That implies that one class's private
> functions can only be friends of another class if the functions are
> public (or possibly protected), or if the whole first class is a friend
> of the second class. (I *assume* the visibility rules apply to
> friendship.)
>
Not quite. A private member function of B cannot be called by an A, but
class A may make a private member of B a friend: B's foo() may
access private parts of A, but A cannot call B::foo().

class B {
public:
B();
private:
void B::foo();
}

class A {
public:
A();

friend void B::foo();
};

Ed Schiebel
AT&T Bell Laboratories
d...@cblph.att.com

Ruud Harmsen

unread,
Mar 29, 1990, 2:39:54 AM3/29/90
to
In article <45...@pegasus.ATT.COM> ps...@pegasus.ATT.COM (Paul S. R. Chisholm) writes:
>[...]

>In article <10...@targon.UUCP>, ru...@targon.UUCP (Ruud Harmsen) writes:
>> Only too true. And isn't this also the fundamental weakness of the
>> object oriented concept? For in the real world, and so in any
>> realistic information system describing a part of that real world,
>> *nearly all* classes are interrelated to *nearly all* other
>> classes.
>> [...]

>As Dr. Koenig pointed out in a later article, "interrelated" means "the
>implementation of one thing depends on the *implementation* of another
>thing".

If the knowledge of the "implementation" of a thing includes to know names
and types of the elements in a structure, it is my experience that some 70
to 80 percent of the code deals with several elements from several
structures, in many different combinations. If then you try to restrict
direct access to the structure elements to functions of the same class,
while providing access from outside the class through functions, you may
have to create an individual function for every element.
This gives me the feeling that calling such a function becomes just a
syntactic variant of the "." and "->" operators, and only obscure things,
and help in no way whatever.

>A "thing" in this case may be a whole class. If you're careful, only a
>few functions in class B (e.g., member function foo and static member
>function bar) will need to know about the implementation of class A; in
>which case, only B::foo and B::bar will need be friends of A. This is
>a Good Thing; it specifically limits what software can mess with an A,
>and what code must be looked at when the implementation of A changes.

> [...]


In theory, this is correct. But if in practice, in a particular
application 70 to 80 percent *has* to mess with a class A, then you can't
do very much limiting.
I think smart cross-reference tools, that tell you where the messing is
done, and also how (read-only, or write-also) it is done, are much more
useful, and can be applied to traditional languages just as well.

Paul S. R. Chisholm

unread,
Apr 3, 1990, 1:03:11 AM4/3/90
to
In article <11...@targon.UUCP>, ru...@targon.UUCP (Ruud Harmsen) writes:
> If the knowledge of the "implementation" of a thing includes to know
> names and types of the elements in a structure, it is my experience
> that some 70 to 80 percent of the code deals with several elements
> from several structures, in many different combinations.

That's bad news. One of the big discoveries of the 70's was that you
should minimize knowledge of a data structure's implementation. Thus
the name "abstract data types", types whose behavior you knew but whose
guts were a total mystery to you. This philosophy leads to reduced
coupling between modules, a reduction in subtle bugs (where one routine
"knew it was all right" to do something that wasn't all right, or once
was all right but changed), and eased maintanance.

Something that came out of work with abstract data types was
"encapsulation": the idea that a data type consists of an
implementation, which (one hopes) is largely hidden, and an interface,
a set of operations objects of that type are capable of. The
implementation of the operations usually assume that functions outside
the type definition can only muck with the objects in certain ways.
(Check out the discussion of assertions in this group.)

Nearly all OOP languages have lots of data hiding, along with
encapsulation. I think the object Pascal implementations are the major
(only?) exceptions.

> . . . If then you try to restrict direct access to the structure


> elements to functions of the same class, while providing access from
> outside the class through functions, you may have to create an
> individual function for every element. This gives me the feeling
> that calling such a function becomes just a syntactic variant of the
> "." and "->" operators, and only obscure things, and help in no way
> whatever.

Exactly right! So don't do it. Such functions are useful if you want
to give limited access to the internals of a structure, which may
change in time. The classic example is a complex data type, which may
story real and imaginary parts, or may store maginitude and angle, or
may change its mind as it sees fit. There are functions x, y, r, and
theta; but some or all of them may do something other than returning a
member.

I wrote:
> >A "thing" in this case may be a whole class. If you're careful, only a
> >few functions in class B (e.g., member function foo and static member
> >function bar) will need to know about the implementation of class A; in
> >which case, only B::foo and B::bar will need be friends of A. This is
> >a Good Thing; it specifically limits what software can mess with an A,
> >and what code must be looked at when the implementation of A changes.

> In theory, this is correct. But if in practice, in a particular


> application 70 to 80 percent *has* to mess with a class A, then you can't
> do very much limiting.

Exactly right. That's the signature of a poor design. You have to
*try*, hard, to hide the implementation of your data types. Twenty
years of programming have taught me that it's worth the effort. Lots
of other believe it, too.

> I think smart cross-reference tools, that tell you where the messing is
> done, and also how (read-only, or write-also) it is done, are much more
> useful, and can be applied to traditional languages just as well.

If they tell you that seventy to eighty percent of the code is "at
risk", they're just telling you that you've got a *lot* of work ahead
of you if you try to change the implementation. A good design is
easier to work with than a bad design, almost regardless of tools.

Ruud Harmsen

unread,
Apr 5, 1990, 5:59:06 AM4/5/90
to
In article <45...@pegasus.ATT.COM> ps...@pegasus.ATT.COM (Paul S. R. Chisholm) writes:
>I wrote:
>> >A "thing" in this case may be a whole class. If you're careful, only a
>> >few functions in class B (e.g., member function foo and static member
>> >function bar) will need to know about the implementation of class A; in
>> >which case, only B::foo and B::bar will need be friends of A. This is
>> >a Good Thing; it specifically limits what software can mess with an A,
>> >and what code must be looked at when the implementation of A changes.
>
I wrote:
>> In theory, this is correct. But if in practice, in a particular
>> application 70 to 80 percent *has* to mess with a class A, then you can't
>> do very much limiting.
>
>Exactly right. That's the signature of a poor design. You have to
>*try*, hard, to hide the implementation of your data types. Twenty
>years of programming have taught me that it's worth the effort. Lots
>of other believe it, too.

I really hope you, and the other believers, are right. But I'm not
convinced. I don't think the trouble is in bad design, I think it's
in the nature of things. The world simply isn't simple, cannot be
forced into strict hierarchical models (remember hierachical databases,
how much trouble they cause(d) in designing a system?), and any design
method that ignores or simplifies these facts, will eventually fail.

But I am always willing to learn, and I will keep on trying to apply
the theories, because I do believe the principles you mention are
themselves useful, and will help a bit, only not as much as many
people seem to think.

>I'm not speaking for the company, I'm just speaking my mind.

So am I.

Ruud Harmsen.

Ruud Harmsen

unread,
Apr 5, 1990, 6:16:28 AM4/5/90
to
In article <45...@pegasus.ATT.COM> ps...@pegasus.ATT.COM (Paul S. R. Chisholm) writes:
>> In theory, this is correct. But if in practice, in a particular
>> application 70 to 80 percent *has* to mess with a class A, then you can't
>> do very much limiting.
>
I wrote:
>Exactly right. That's the signature of a poor design. You have to
>*try*, hard, to hide the implementation of your data types. Twenty
>years of programming have taught me that it's worth the effort. Lots
>of other believe it, too.

Perhaps it all depends a lot on the kind of application. In the ones
I dealt with most (financial accounting, invoicing, banking etc.) the
implementation of the data types, say the fields of the structs, are
exactly what the *user* of the system deals with, viz. enters, browses,
prints, talks about with his clients, etc.

How could it be useful to *hide* these things, if to the *user* of the
system, they are the only things that matter? If you hide the data-items,
nothing useful remains.

I can imagine that in other sorts of applications, perhaps an operating
system, or a graphics system, this is quite different.
For example, the UNIX implementation of buffered IO is built in an
OO-fashion, and I am very content that I don't have to know what exactly
hides behind the type FILE, to be able to use it. But now tell
a bookkeeper he doesn't need to know what data items are in the system
about his debtors!

So maybe that's why we may well be both right, and simply talking ahead of
each other, because we simply don't have the same kind of systems in mind?

Lucio de Re

unread,
Apr 9, 1990, 6:52:57 PM4/9/90
to
In article <11...@targon.UUCP> ru...@targon.UUCP (Ruud Harmsen) writes:
>In article <45...@pegasus.ATT.COM> ps...@pegasus.ATT.COM (Paul S. R. Chisholm) writes:
>I wrote:
>>> In theory, this is correct. But if in practice, in a particular
>>> application 70 to 80 percent *has* to mess with a class A, then you can't
>>> do very much limiting.
>>
>>Exactly right. That's the signature of a poor design. You have to
>>*try*, hard, to hide the implementation of your data types. Twenty
>>years of programming have taught me that it's worth the effort. Lots
>>of other believe it, too.

I am one of those believers. Fortunately for us programmers, the
reality we have to contend with is seldom of such a nature that
abstraction cannot reduce it to the point where classes provide
an adequate description. Even Modula 2, without the object oriented
abstractions did a formidable job of data hiding and at the same
time simplified coding. I appreciate that it is difficult to isolate
individual classes at a glance in a great many instances, and I
presume no proof is available to demonstrate that a class concept
is general enough to cover all instances of programmable tasks
(wow, what a mouthful!); I also think that Paul Chisholm used
excessively strong terminology in "the signature of a poor design,"
but his point is valid, better design will produce one or more
classes more faithfully modelling the system underscrutiny (I must
stop this pompousness, please no flames!).

Remember that inheritance, and particularly multiple inheritance,
with its greater complexity, ought to extend the power of object
oriented design to (hopefully) all programmable instances. It
probably doesn't, as there is an infinite amount of complexity out
there and (I guess) a finite number of constructs programmers can
design, but somebody better versed in mathematical theory than I
should attempt a proof in either direction while we programmers
continue with our heuristic approach to problem solving.

>I really hope you, and the other believers, are right. But I'm not
>convinced. I don't think the trouble is in bad design, I think it's
>in the nature of things. The world simply isn't simple, cannot be

>forced into strict hierarchical models ...

I suppose the proof of the pudding ... I contend that (a) you are
correct in believing that hierarchies are not sufficient to represent
all possible conditions, but (b) the problems that programmers face
in (say) 90% of instances have solutions that can be decomposed into
hierarchical representations, and (c) that careful analysis and possi-
bly a fair amount of thumb-sucking guesswork can bring whatever the
initial percentage might be a lot closer to a 100% of all USEFUL
applications.

My fear, and perhaps it is Paul's fear as well, is that because the
object-oriented model is not always immediately obvious, the program-
mer may overlook it and use a (currently) more traditional approach.

I suggest that when a problem that looks as if it does not lend itself
to decomposition into object oriented classes occurs, it should be
submitted for scrutiny on this forum. I believe that the field is
young enough for all of us to have something to learn from the
experiences of others, while at the same time the presenter should
weigh the (possible) embarrassment of having the obvious pointed
out to him/her (and I do not exclude the possibility that the forum
may not succeed in the quest for a suitable representation, to the
embarrassment of the forum in its entirity) against the possibility
that an elegant solution may simplify immediate programming (unlikely
as we all have deadlines to work to), and certainly future maintenance.

----------------------------------------------------------------------
I used to design nuclear reactors and you should see the code that
engineers and scientists come up with. Yuuuck! Spaghetti everywhere.
-------------------------------------------------- (Kenneth L Moore) -
Lucio de Re ...uunet!ddsw1!olsa99!proxima!lucio
-------------------------------------------------------- lucio@proxima
Disclaimer: He must have been joking!

Lucio de Re

unread,
Apr 9, 1990, 7:08:08 PM4/9/90
to
In article <11...@targon.UUCP> ru...@targon.UUCP (Ruud Harmsen) writes:
>Perhaps it all depends a lot on the kind of application. In the ones
>I dealt with most (financial accounting, invoicing, banking etc.) the
>implementation of the data types, say the fields of the structs, are
>exactly what the *user* of the system deals with, viz. enters, browses,
>prints, talks about with his clients, etc.
>
>How could it be useful to *hide* these things, if to the *user* of the
>system, they are the only things that matter? If you hide the data-items,
>nothing useful remains.

I think there is some confusion here. I presume (and I'm a bit of a
novice at this, so please be tolerant) that, whereas the *user*does*
want to see the fields separately, they are grouped at all times and
are very seldom manipulated out of context. Nobody contends that the
fields are not disjoint, but, in APL parlance, changing one element
of a matrix affects the matrix as a whole. Likewise, changing the
balance on a debtor record affects the entire record. Let's take one
example: Let's say that the internal representation of a debtor
consists of a master file record with debit and credit balances,
current and prior to the present, as well as the (active) history
in the form of transactions. It is arbitrary whether one wants the
occurrence of a new transaction to affect the debtor's balance in
the master file record or not, but it is not arbitrary that the
actual debtor's balance _is_ affected. Good design dictates that
the representation of the debtor in the computer system should be
such that the master file record is tightly coupled to the
transaction records, so that they are viewed by the system as a
single entity. That is how I perceive OOP to function, not as a
limiting factor that forces all objects to be lumped together, but
rather providing a unification glue so that aspects that belong
together are always kept that way.

Sorry to soapbox like this, I hope I haven't muddled the concepts
beyond understanding.

David S. Masterson

unread,
Apr 9, 1990, 1:36:25 PM4/9/90
to
In article <11...@targon.UUCP> ru...@targon.UUCP (Ruud Harmsen) writes:

Perhaps it all depends a lot on the kind of application. In the ones
I dealt with most (financial accounting, invoicing, banking etc.) the
implementation of the data types, say the fields of the structs, are
exactly what the *user* of the system deals with, viz. enters, browses,
prints, talks about with his clients, etc.

How could it be useful to *hide* these things, if to the *user* of the
system, they are the only things that matter? If you hide the data-items,
nothing useful remains.

Even in these types of applications, there is more to be concerned with than
just the structure of the data. There may also be rules that go with the
data. For instance, updating an employee's record may invoke a rule against
the company's financial records. This may not be hidden from the user (or it
may), but the business rule must occur and, so, should be "tied" to the
employees data structure. Sometimes (oftentimes), it is useful to hide this
tie from the "ordinary" user who is not allowed to change the rule anyway.
--
===================================================================
David Masterson Consilium, Inc.
uunet!cimshop!davidm Mt. View, CA 94043
===================================================================
"If someone thinks they know what I said, then I didn't say it!"

Paul S. R. Chisholm

unread,
Apr 15, 1990, 1:42:53 AM4/15/90
to
This is getting long, but staying interesting. You should be able to
skim or skip the quoted old text, thought it's still relevent enough to
include. At Ruud's implicit invitation, I've venture a little bit into
database land; it gets back to C++ and OOD near the end.

In article <45...@pegasus.ATT.COM> ps...@pegasus.ATT.COM (Paul S. R. Chisholm)

(that's me) writes:
> If you're careful, only a few functions in class B (e.g., member
> function foo and static member function bar) will need to know about
> the implementation of class A; in which case, only B::foo and B::bar
> will need be friends of A. This is a Good Thing; it specifically
> limits what software can mess with an A, and what code must be
> looked at when the implementation of A changes.

In some article (<11...@targon.UUCP>, I think), ru...@targon.UUCP (Ruud


Harmsen) writes:
> In theory, this is correct. But if in practice, in a particular
> application 70 to 80 percent *has* to mess with a class A, then you
> can't do very much limiting.

I wrote:
> Exactly right. That's the signature of a poor design. You have to
> *try*, hard, to hide the implementation of your data types. Twenty
> years of programming have taught me that it's worth the effort.
> Lots of other believe it, too.

Ruud wrote:
> Perhaps it all depends a lot on the kind of application. In the
> ones I dealt with most (financial accounting, invoicing, banking
> etc.) the implementation of the data types, say the fields of the
> structs, are exactly what the *user* of the system deals with, viz.
> enters, browses, prints, talks about with his clients, etc.

Not at all. The simplest way to describe data is to describe the
values or attributes associated with it, and, yes, they must be
visible, maybe even writable, by users. But that's *not* saying that
the user must know how the software represents the data.

The most common (to the point of over-re-use:-) example is imaginary
numbers. Everybody "knows" that an complex number consists of a real
part and an imaginary part, right? Except that a complex number can
also be represented as a magnitude and an angle. The user may ask for,
or try to set, those attributes; he or she may do calculations that
would be easier if the number was represented that way.

One alternative is to have your class remember x, y, r, and theta, and
a flag that says which of the two representations is up-to-date. (This
is different still than the way you'd store this in a database.) If
you set x, there'd be no change to y, and r and theta would be listed
as being out-of-date. If you multiplied two complex values, their x's
and y's would be brought up-to-date (yeah, a side effect to addition;
but only as an efficiency hack), and the sums of the x's and y's would
be stored in the complex sum. This doesn't just twiddle performance,
it relieves most of the complex class functions from knowing which
representation was really used. (The opportunities for trivial inline
functions are left as an easy exercise for the reader.)

> How could it be useful to *hide* these things, if to the *user* of
> the system, they are the only things that matter? If you hide the
> data-items, nothing useful remains.

Not at all. The idea of having different views of a database is quite
common. Let's take the example of a student database. Some
attributes should only been seen by some applications. (This should
*really* be done with some sort of access bits in the database, but I
want to bring this example back to C++.) You could have a parent class
where all of the data members are protected. Various subclasses could
provide read and/or write access, via member functions, to these data
members. (You could have a subclass for each read access function, and
another for each write access function, and multiply inherit only what
you needed.) You could also have access functions for values that
aren't stored in the database records, such as accumulative GPA.

> I can imagine that in other sorts of applications, perhaps an
> operating system, or a graphics system, this is quite different.
> For example, the UNIX implementation of buffered IO is built in an
> OO-fashion, and I am very content that I don't have to know what
> exactly hides behind the type FILE, to be able to use it. But now
> tell a bookkeeper he doesn't need to know what data items are in the
> system about his debtors!

Okay, I'll tell him or her exactly that! He or she should, of course,
know what data items are in the bookkeeper *view* of the database. But
only the database administrator, and some of the database API writers,
need to know what's physically in the database. With some effort made
up front, not even the developer of the bookkeeper's software has to
know the structure of anything but the view.

Let me leave the examples behind and tie things back up. The enemy I
fight as a software engineer is software complexity. My best weapon in
this fight is to limit representation information to various small,
well isolated parts of my design (and my code). That in turn limits me
to some well defined interfaces (e.g., C++ member functions), which act
as firewalls when representational changes catch fire in one part of my
software.

> So maybe that's why we may well be both right, and simply talking
> ahead of each other, because we simply don't have the same kind of
> systems in mind?

What we're talking about is, to me, one of the big differences between
being a programmer and being a software engineer. Which is *NOT* to
say that Ruud isn't a software engineer; or that there aren't task that
a programmer can accomplish faster than, and as well as, a software
engineer. A software engineer should be willing to sweat the design
harder up front, to save time in the hypothetical case where big
changes could cause big problems.

Richard Sargent

unread,
Apr 18, 1990, 10:00:27 AM4/18/90
to
A number of people have been discussing what is visible within a class
and what the user needs to know in order to do his work. Paul Chisolm
touch the land of database, and I feel that is where the answer lies.

Disclaimer: I am not a DB guru, so I may not say this exactly right...

Essentially, you have two 'views' of the system's data: logical and
physical. The former corresponds to the user's conceptual understanding
and the latter corresponds to how it is actually stored. There can
be quite a difference between the two views, provided your software
supplies the correct mapping.

This is what I think we have to do to handle this issue.

Richard Sargent Internet: ric...@pantor.UUCP
Systems Analyst UUCP: ...!mnetor!becker!pantor!richard

Ruud Harmsen

unread,
Apr 18, 1990, 9:50:36 AM4/18/90
to
In article <12...@proxima.UUCP> lu...@proxima.UUCP (Lucio de Re) writes:
> I suggest that when a problem that looks as if it does not lend itself
> to decomposition into object oriented classes occurs, it should be
> submitted for scrutiny on this forum. I believe that the field is
> young enough for all of us to have something to learn from the
> experiences of others, while at the same time the presenter should
> weigh the (possible) embarrassment of having the obvious pointed
> out to him/her (and I do not exclude the possibility that the forum
> may not succeed in the quest for a suitable representation, to the
> embarrassment of the forum in its entirity) against the possibility
> that an elegant solution may simplify immediate programming (unlikely
> as we all have deadlines to work to), and certainly future maintenance.

OK, here we go. (BTW, I don't mind any embarrassment, as long as I can
learn from it).

Suppose, we have a system for order registration, and invoicing.
(to name only the two most complicated programmes in such a system).

Object classes are: (Assuming that what are third normal form tables in
a relational database design, are also object classes; is that wise?)

- customers
- customer groups
- articles
- article groups
- orders
- order positions
- price finding schemes, per article group
- special action prices, per article and per period
- special price benefits per costumer
- special price benefits per costumer group
- special prices in case of larger quantities at once
(conditions may vary for various costumer groups).

When an order from a costumer is taken, you have to precalculate what
it is going to cost, to see if you want to give that much credit.
So you have to have a price calculation algorithm, the details of which
I would like to hide somewhere in a class (it will be re-used in the
invoicing programme too, of course).
But which class should I choose?
One of those I mentioned? A price-class of its own? Whatever I do,
the algorithm needs data from *all* of the classes I mentioned above.
So will this function be friends with all the others? Or will they
all provide functions that return the requested information? Or will
the whole system be just one large class? Or did I chose the classes wrong?

I hope someone knows the answers, and if so, that these answers are easier
and clearer than the traditional approach, of just getting such a programme
to work, using all the common sense you can find. For it is not enough if
OOP can do this too, it is required that with OOP we can develop faster,
better maintainable, etc.

Ruud Harmsen.

PS. If by any chance I suddenly don't react to your reactions anymore,
it's *not* because I'm annoyed, but because these are the last couple of
days at this job, and I won't be connected to the net anymore after 23rd
April.

NE...@cgi.com

unread,
Apr 19, 1990, 11:31:56 AM4/19/90
to
The "friend" construct is present in C++ because sometimes, there really is a
need to break the data encapsulation and allow a function or other class to
have access to the internals of some class. However, I don't like doing this
very often, if at all. I generally restrict friendship to a specific function,
but this too can be dangerous, since I am forced to expose *ALL* the private
data and member functions when it is more likely that I really just want access
to one or two pieces, not the entire thing.

What I would really like to do is restrict an outside function or class to be a
friend of some subset of the private components. Now I realize that the syntax
for this could be quite hairy, especially if someone gets carried away and
tries to name 27 different private data members that could all be accessed by
the friend function. One possible solution would be to allow multiple friend
specifications with one private data member or member function per statement.
Something like the following would work (syntax is very open to suggestions!):

class foo {
private:
float a,b;
public:
void init(void);
};

class bar {
private:
int x,y;
void reset(void);
friend void foo::init(void) int x;
friend void foo::init(void) void reset(void);
public:
void dummy(void);
};

In this example, the public member function foo::init() would be a friend of
class bar and have access to the private data member "x" and the private member
function "reset". It would not, however, have access to data member "y". In
addition to providing finer granularity over the selection and specification of
friendship, something like this would also be compatible with the existing
"friend" rules and syntax.

Regards
Martin Neath <ne...@itg.ti.com>
------------------------------------------------------------------------
DISCLAIMER: As always, the opinions expressed above are strictly my own
and do not reflect those of my employer, Texas Instruments.
------------------------------------------------------------------------

joh...@p.cs.uiuc.edu

unread,
Apr 20, 1990, 12:29:23 PM4/20/90
to

I'll take a crack at Ruud Harmsen's order registration system. I worked
on something similar years ago, and it was one of the main things that
got me interested in object-oriented programming.

The initial set of classes is:

- customers
- customer groups
- articles
- article groups
- orders
- order positions
- price finding schemes, per article group
- special action prices, per article and per period
- special price benefits per costumer
- special price benefits per costumer group
- special prices in case of larger quantities at once
(conditions may vary for various costumer groups).

The problem is to write an algorithm to compute the price of an order.

I'm not exactly sure what an article group and a customer group is.
I assume that they are attributes of articles and customers, i.e.
if a customer is in a particular group than it will get certain kind
of price breaks. Perhaps a customer group only determines certain
values, so it can be implemented as a table of values. However, if
it determines algorithms then it probably implies subclasses, i.e.
there should be a subclass of Customer for each customer group. If
customer groups overlap don't overlap then this is certainly the
right way to think about it. If they do overlap then this might
imply multiple inheritance, although it also might imply that we are
thinking about it all wrong.

In any case, I think that a customer group is an attribute of a
customer. Moreover, special price breaks to customers is also an
attribute of a customer, and the rest of the system does not need
to know it. A Customer should be able to tell you the price of an
Article, and it is responsible for knowing special price breaks.

Naturally, the same thing goes for Articles and their groups.
In fact, the line "price finding schemes, per article group" is
a dead giveaway that article groups are really subclasses of articles.

The class organization is now

- customers
subclasses represent groups
private information represents special price benefits

- articles
subclasses represent groups
private information represents special price benefits

- orders
- order positions

An order has one customer and lots of articles, with various
quantities of each article. There is an operation cost() on
orders that returns its price. It delegates the work to a
findCost() operation in Customer that sums up the costs of the
individual articles. The cost of an article is found with
article.cost(customer, number)
which uses double dispatching to pick a method based on the class
of both the article and the customer, so each can have special
rules for calculating costs. After suming the costs of the articles,
the findCost() operation in Customer can use customer-specific
quantity discount algorithms to find the final cost.

How does this sound?

Ralph Johnson

Tony Davis

unread,
Apr 20, 1990, 8:44:50 PM4/20/90
to
I'm glad this question came up; I think design issues are something
worth considerably more discussion in this group. Unfortunately,
for the problem in question I don't think we have enough information
to do a proper job. As such what I say below may seem like an attack
since I won't be offering a complete alternative design. Be assured
it is not, but I feel at this point C++ needs considerable care to
avoid bad design decisions in large systems which will turn people off
to what is a very complex language.

In article <7730...@p.cs.uiuc.edu> joh...@p.cs.uiuc.edu writes:
[ The problem ]


>I'll take a crack at Ruud Harmsen's order registration system. I worked
>on something similar years ago, and it was one of the main things that
>got me interested in object-oriented programming.
>
>>The initial set of classes is:
>>
>>- customers
>>- customer groups
>>- articles
>>- article groups
>>- orders
>>- order positions
>>- price finding schemes, per article group
>>- special action prices, per article and per period
>>- special price benefits per costumer
>>- special price benefits per costumer group
>>- special prices in case of larger quantities at once
>> (conditions may vary for various costumer groups).
>>
>>The problem is to write an algorithm to compute the price of an order.

>I'm not exactly sure what an article group and a customer group is.

Which is why we can't do a proper design job over the network, but lets
work with assumptions so that we can say something. As Mr. Johnson
attacks immediately below, we need to determine what are the objects
and how do they relate. There are numerous methodologies for determining
this, but as a basis for an ad hoc discussion, keep the real world in
mind, it provides a guide post to developing an understandable and therefore
more maintainable system. In my real world, customers, articles, and
orders are objects. Customers are real world people. Articles are the
item for sale? Orders might be considered the relationship between
customers and articles. Even in the real world, orders are more
nebulous things, but we know something about them. In the real world
(as opposed to the computer world), we would fill out a paper form
to place an order. The information on that form represents our real
world concept of what an order is. (To be sure, once we've incorporated
orders into a computer representation, they can be much easier to
change. However, when explaining the system to a new programmer it can
be very powerful to say "Orders? Oh, they just represent the information
we would need on a paper form to place an order." Your implementation
of orders might contain support for an automatic accounting system.
Nonetheless, the general notion can conveyed be very quickly.)

>I assume that they are attributes of articles and customers, i.e.
>if a customer is in a particular group than it will get certain kind
>of price breaks.

Keeping the real world in mind, customer groups are not something we
usually attribute to people. A customer group (if our conceptions
about the problem are correct) is simply a collection of people. This
might be implemented underneath as a linked list, a hash table,
or even an interface into a database indexing mechanism, but the
interface to the outside world (including the rest of the program)
can simply be a group of people. The group can be extended to represent
information specific to the group. Thinking ahead about the
application, we can realize that the price calculating algorithm
may need to know what groups a customer is in and searching all the
groups would be prohibitively expensive. In this case it's perfectly
reasonable to design a Customer type which can tell you what groups
it is in. We can imagine real people knowing what groups they belong
to, although in the specific case of customers, they may not be likely
to know what pricing groups they are categorized in within some company
that they deal with. The point is that Customers know the groups they
belong to as an implementation detail; it is not how we define groups.
Given a Customer, the algorithm might ask the Customer what groups it
belongs to, then query each group for group specific information. This
doesn't require friend functions to implement. Nonetheless, the separation
between Customers and Groups provides understandability, maintenance, and
reuse advantages.

>Perhaps a customer group only determines certain
>values, so it can be implemented as a table of values. However, if
>it determines algorithms then it probably implies subclasses, i.e.
>there should be a subclass of Customer for each customer group. If

>customer groups [...] don't overlap then this is certainly the


>right way to think about it.

I must strongly disagree. Differing algorithms imply subclasses only
if 1) the algorithm concerns the superclass in the first place, and
2) differing kinds of objects of the common superclass imply differing
behaviours. Differing subclasses may work as an implementation
technique for the pricing algorithm (see below), but it may be that the
differences are simply historical artifacts of company history which
don't have any common meaning. For guidance, back to the real world:
pricing is not something that customers know, Customers should not know
it either. The question natural arises: Who/what does know about pricing?
If we wanted to carry the real world analogy further, we can ask "Who
determines prices in the real world?" That can be answered and simulated,
but carrying the real world analogy too far leads to programs that model
the real world and have its attendant problems: it's big, slow, and
complex, :-) so you have to stop somewhere. Lets leave that question
unanswered for now.

>If they do overlap then this might
>imply multiple inheritance, although it also might imply that we are
>thinking about it all wrong.

They will almost certainly overlap. If you sell a customer one thing,
you will want to sell them another perhaps applying an additional
customer group. In this case I think multiple inheritance does imply
a wrong approach to the problem. Multiple inheritance implies a wrong
approach when it is used as an implementation technique to work around
bad design decisions. Of course, it is hard to tell the difference
between cases where multiple inheritance is suggested because of previous
bad design and cases where a design is still evolving and effective
uses of multiple inheritance come up as the design is elaborated. In
any case, multiple inheritance in C++ is complex and often inefficient
(compared to single inheritance, not compared to other languages), so
suggestions of multiple inheritance immediately raise a red flag with
me. Multiple inheritance can be very useful as a design tool, it is
rarely useful alone as an implementation tool. Hence, multiple
inheritance is not nearly as valuable as many people think it is.

(These are strong statements. I expect people to disagree with them.
Please post contrary opinions. They would be portions of the design
discussions I would want to promote. I think design questions are
the killers that may eventually end the object oriented craze (note,
'end the craze', I think object oriented methods are an improvement).
C++ provides efficient object oriented programs, but because of design
issues, that is not enough to sell 'object oriented' as a panacea.)

In this case, the problems with multiple inheritance are evident in
the implementation. Consider selling a customer something they
haven't bought before which also requires them to be added to another
Customer group. If the resulting Customer group combination didn't
exist before, the system would have to be reprogrammed to add the class.
In practice this wouldn't happen; all customers would simply be put
into the same group.

Another problem with a multiple inheritance solution is the number of
types that would be needed. If there are N customer groups, full
enumeration of the possible overlapping combinations would require
2 to the N types. The system in operation is not likely to require
all of these types, nonetheless, the types that would be needed are
likely to be numerous enough to cause significant maintenance problems.

>In any case, I think that a customer group is an attribute of a
>customer. Moreover, special price breaks to customers is also an
>attribute of a customer, and the rest of the system does not need
>to know it. A Customer should be able to tell you the price of an
>Article, and it is responsible for knowing special price breaks.

As you can imagine by now, again I must disagree for reasons partially
explained above. Also, according to the problem, pricing is the
purpose of the whole system. If a Customer can tell you prices and
price breaks, is it the whole system? For my real world analogy,
pricing is the cutoff point between the program and the real world.
The program only needs to implement a pricing system, not model the
entire world. As reasoned above, pricing information is not something
customers would know. Further, that Customers can answer the question
that the whole system is to answer, suggests either that Customers *are*
*really* the whole system or that a bad design has given them too
much responsiblity. Again the difference is hard to determine.

>Naturally, the same thing goes for Articles and their groups.
>In fact, the line "price finding schemes, per article group" is
>a dead giveaway that article groups are really subclasses of articles.

If anything, the quoted line suggests a relationship between price
finding schemes and article groups, but not necessarily with articles
themselves. First, however, we must decide whether price finding
schemes should belong to some other object at all. It may be that the
overall solution takes a Customer, an Article, and a PriceScheme (a class
that stands alone) and returns an Order with the Price filled in.
Or it may be that the system gives a Customer and an Article to
a PricingAgent (a represented real person subclassed from Employee?)
which determines a Price to be used later in an Order (since prices
can exist independently of orders (in which case they might be called
Quotes)).

>
>The class organization is now
>
>- customers
> subclasses represent groups
> private information represents special price benefits
>
>- articles
> subclasses represent groups
> private information represents special price benefits
>
>- orders
>- order positions
>

> [...] Ralph Johnson

Note that two different classes know about special price benefits,
both Articles and Customers. Designs like this are sometimes
braced with overuse of friend functions. Friends are another red
flag; sometimes the design requires them, sometimes they simply
shore up implementations of inappropriate designs.

I can't provide a full design, but I think appropriate classes would
include Customers, Articles, and a grouping mechanism useful for both
Articles and Customers. The grouping mechansim might use subclasses or
templates to hold information about the particular group.
Orders, Prices, and Pricing Schemes might qualify as classes as well.
Order Postions might be layering classes within Order objects, but
I'm guessing since I have no idea what they are. It will be exceptionally
hard to design an appropriate Pricing mechanism without knowledge of the
kinds of variablility that it requires.

The design problem is that, of course, the design affects the properties
of the implementation, including functionality, maintainability, and
even workablility, but problems may not be evident until the system or
portions thereof has been implemented. It's a truism that problems with
the design require redesign, but first the design problems must be
recognized. This is where C++ can get in the way. It offers so many
features that one may be tempted to simply apply another feature to fix
a problem without recognizing the nature of the problem. Eventually this
prevents redesign since too much time has already been invested. This
is why red warning flags and real world guideposts can be so valuable.
They help mark the paths of good and bad design.

Please comment.
What are your markers for good and bad design?

Tony Davis
t...@cs.brown.edu

David S. Masterson

unread,
Apr 23, 1990, 2:26:07 AM4/23/90
to
In article <37...@brunix.UUCP> t...@cs.brown.edu (Tony Davis) writes:

I'm glad this question came up; I think design issues are something
worth considerably more discussion in this group.

Actually, I think lengthy discussions of object-oriented design and
object-oriented principles should be directed toward (or at least include) the
comp.object newsgroup.

0 new messages