Topic: Virtual functions: should there be more than one kind?


Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 13 Sep 93 14:40:06 GMT
Raw View


jln2@cec2.wustl.edu (Sammy D. @ Opinions expressed are not necessarily my own!) writes

 (Which of the opinions expressed are yours, then? - bs :-)

 > jemenake@trumpet.aix.calpoly.edu (Joe Emenaker) writes:
 >
 > : So, my question you you folks is: What GOOD is it going to do me to
 > : invest any more time learning C++?
 >
 > The future, I think, isn't with C++, it is with GUI integrated 4th
 > generation interpreters, like Hypercard, Visual Basic, etc.
 >
 > So, to answer Joe's question, no good what so ever.

 ...

 > I learned OOP from Flavors, I knew OOP well, and believe me, C++ is not
 > an OOP language  (apologies to Senator Benson).

If the definition of OOP is Flavors then C++ is indeed not OOP; however,
(almost?) all reasonable people tend to admit languages with static type
checking into their definition of an OOPL provided they provide inheritance
and maybe one or two other distinguishing features. Not doing that would
exclude not only C++, but also Beta, Eiffel, Simula, and many other well
respected OOPLs from the class of OOPLs.

 > Why doesn't C++ give
 > us :before, :after, :and, :or and all the rest.  C++'s way of doing
 > inheritance is like doing structured programming in Fortran 66.

Had I wanted to support dynamic inheritance, I would have done so. I knew
enough Smalltalk, Flavors, and (more recently) CLOS to design a good
imitation had I wanted one. I didn't. If I need a more dynamic system
I know where to find Smalltalk or CLOS. There is (IMO) no need for an
immitation; those languages serve their intended purposes well enough.

C++ provides facilities to express static structure clearly and for
that static structure to be exploited by programmers and enforced by
the implementation. Efficiently. Beyond the paradigms/styles directly
supported by C++ one must simulate. Merely fighting the type system
usually fails.

In my experience, one of the most common reasons for a person to fail
to benefit from C++ is that person having a firm belief that he/she
knows everything worth knowing about programming so that he/she can
simply e to use C++ as a slightly inconvenient notation for their
``one right kind of programming.'' If you want to benefit from C++
you should be prepared to invest some time and energy in learning how
C++ is supposed to serve you.

 > I started listening in on comp.{lang,std}.C++ a week ago, because I
 > thought that C++ could help me with a project I was reengineering.  I'm
 > still listening, but I've decided to recommend staying with C.

Had I know very little about C++ and listened to the rantings on
comp.lang.c++ lately, I suspect I would have drawn the same conclusion.
Many people on comp.lang.c++ patiently, clearly, politely, and correctly
explains what C++ is, what C++ isn't, and shows how one might use it.
Others, however, use comp.lang.c++ to display their ignorance. This, I
fear, is inevitable in a large newsgroup discussing a popular topic and
has very little to do with programming or C++.

If someone decides that they have no wish to be associated with a bunch
of people so rude and opinionated as some of the people arguing here,
I can't really blame them. Similarly, if someone decides that a language
where one has to know details as obscure as some of the ones debated here
is too subtle to bother with, then again I can't blame them.

Fortunately, it just isn't so. Most C++ programmers are as polite and
helpful as other people, and you don't have to understand the subtleties
discussed in the standards meetings to use C++ successfully.

Novices (relative to a particular language) do not learn good programming
form hearing experts and would-be experts debate subtle points; they learn
from textbooks, from courses, and from reading code. One thing we all have
to learn is that relatively to a new significant programming language we are
all novices. ``The net'' can also answer specific questions, but it seems
unable to help people choose which questions to ask and it is not easy for a
novice to know which answers to believe.

In particular, we ought to try to place discussions of subtleties on
comp.std.c++ and to place discussion of practical uses on comp.lang.c++.
Hopefully, this would allow the novices to learn from the more experiences
on comp.lang.c++ and the experts to demonstrate their erudition on comp.std.c++.
Unfortunately, flame wars are often so much more interesting than presenting
simple explanations to the novices who needs them :-( Similarly, arguing
subtleties with language lawyers seems to have a perverse attraction.

I don't know if this reassures people or not, but I have a hard time seeing
the point in some of the discussions and in following the twists and turns
of the subtle arguments. Such arguments are at times necessary to resolve
issues, but it is not what C++ programming is about.

 > This
 > makes the third time in as many years I've looked hard at C++, and my
 > decisions are always the same.

It sounds like you dislike or doesn't need static structure and/or static
type checking. If so, your decision is probably correct. Fake the dynamic
inheritance mechanisms in C (or the C subset of C++), or even better use
a language designed to support your style.

One might also suspect that you haven't looked very hard and maybe in the
wrong places:

 > Actually, my C++ knowlege stinks.  I looked at a few years ago when
 > Borland first offered their C++ compiler, dropped it, tried it again
 > about a week ago and have decided to drop it again.

I don't think you can learn C++ in a week. At least, I know that most good
programmers can't learn C++ in a week. That is, actually, one thing people
keep remarking on as a GOOD thing. You don't exhaust the language in a
week or a month but continue to learn new things and gain concrete benefits
from new techniques and concepts month after month.

 > What don't I like?  Well, besides the preceeding, look at any of the
 > "how many angels on the head of a pin" arguments going on in
 > comp.std.c++ (matching argument lists to overloaded functions seems to
 > be particularly hot right now).

You don't need to know physics or patent law to drive a car and you don't
need to understand the discussions on comp.std.c++ or in the standards
committees to write good C++. In fact a focus on physics or law will make
you a worse driver - and a focus on obscure language details will make you
a worse C++ programmer.

 > Look that the presumably experienced
 > programmers asking "why can't I do X, Y, or Z?" and getting told that a
 > page of arcane code will fix their problem

Many of the questions are of the form ``why can't I do X exactly as I did
it in my previous language?'' Maybe the kindest answer would b be ``because
that's not the way we do it in C++,'' but people here tend to be kind and
helpful and try to provide C++ equivalents to alien paradigms. Some of the
discussion reminds me of the imperial/metric metrics debates: ``why would
anyone what to calculate distance in 1614.2 meters? (or whatever) it is so
much easier to say 7 miles than 11299.4 meters!'' You try to use each system
for what it is good at and direct exact translations are NEVER convenient.

 > (one of my pet peeves is
 > that it is apparently impossible to directly cast a va_list into a
 > (char**) to pass to execv, but scores of similar examples abound).

If that (whatever it is) is impossible in C++ it is equally impossible in C.
It sounds to me like a confusion about how C (and maybe therefore C++) works.

 > Simultaneously, other C++ promoters will argue that C++ generates code
 > just a efficient as C.

Equivalent code is at least as efficient. Non-equivalent code can be more
or less efficient dependent on exactly how it is non-equivalent.



So how would I answer Joe or any other person wondering whether it is
worth while to learn C++?

The real question is ``What do you want from a programming language?''

For many programmers, C++ is simply much more fun than C or Pascal.
This is important if you have to spend years programming. There are
language that are even more fun for particular tasks or for particular
parts of a programmer's work, but none, I think, that is as helpful
over as broad a range of problems.

For many, this ``fun'' comes from being able to express ideas more
clearly, from being able to learn new concepts and techniques and
apply them, from being relieved from some of the more tedious aspects
of C and Pascal programming, and from a feeling of doing a better job.

For many managers, the key to C++ has nothing to do with programming
language constructs or programming. To them the decrease in maintenance
cost (say, a factor two compared to C) is what they like.

The question to ask the net is not ``What good is C++ in general?'' but
``what good is C++ relative to my particular needs?'' The former question
can only be answered by generalities (usually somewhat vague), the latter
can be answered by concrete arguments and examples, and can usually be
backed up with references to the extensive literature about C++ and its
use.

So if you want to learn C++, first figure out why C++ might help you.
Trying to learn C++ just because ``everybody uses in'' (not everybody
does use C++ and not should use C++) or because someone promised you
that ``it performs miracles'' (it doesn't) is silly. Unless you have
a pretty good idea of what you want and how you are going to achieve
it you'll most likely fail - in any language.

Next, be reasonable about your expectations. C++ delivers benefits
proportionally to your understanding of the techniques you know how
to use. You can use C++ as simply a better C and gain some benefits,
but learning abstraction techniques and object-oriented programming
is the way to greater benefits.

To learn those techniques and their use with C++ you need a textbook,
not just a manual or a superficial ``how to'' guide.

 - Bjarne

PS I'll repost a long message I wrote about learning C++; it might
be useful in this context. Apologies to people who have seen it before.




Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 13 Sep 93 14:40:40 GMT
Raw View


There has - under various headings - been several related discussions
about the proper way to learn C++, C++'s relation to C, C++'s relation
to Smalltalk, the difference (or not) between data abstraction and
object-oriented programming, etc.


I think the practical concern underlying many of these discussions is:

 Given that I don't have much time to learn new techniques
 and concepts, how do I start using C++ effectively?

It is clear that to use C++ ``best'' in an arbitrary situation you
need a deep understanding of many concepts and techniques, but that
can only be achieved through years of study and experiments. It is
little help to tell a novice (a novice with C++, typically not a
novice with programming in general), first to gain a thorough
understanding of C, Smalltalk, CLOS, Pascal, ML, Eiffel, assembler,
capability based systems, OODMBSs, program verification techniques,
etc., and then apply the lessons learned to C++ on his or her next
project. All of those topics are worthy of study and would - in the
long run - help, but practical programmers (and students) cannot
take years off from whatever they are doing for a comprehensive
study of programming languages and techniques.

On the other hand, most novices understand that ``a little knowledge
is a dangerous thing'' and would like some assurance that the little
they can afford time to learn before/while starting their next project
will be of help and not a distraction or a hinderance to the success
of that project. They would also like to be confident that the little
new they can absorb immediately can be part of a path that can lead
to the more comprehensive understanding actually desired rather than
an isolated skill leading nowhere further.

Naturally, more than one approach can fulfill these criteria and
exactly which to choose depends on the individual's background,
immediate needs, and the time available. I think many educators,
trainers, and posters to the net underestimate the imporatance
of this: after all, it appears so much more cost effective - and
easier - to ``educate'' people in large batches rather than
bothering with individuals.

Consider a few common questions:

 I don't know C or C++, should I learn C first?

 I want to do OOP, should I learn Smalltalk before C++?

 Should I start using C++ as an OOPL or as a better C?

 How long does it take to learn C++?

I don't claim to have the only answers ``the (only) right answers''
to these questions. As I said the ``right'' answer depends on the
circumstances. Most C++ textbook writers, teachers, and programmers
have their own answers. For example, I seem to remember that the C++
FAQ discusses these questions. My answers are based on years of
programming in C++ and other languages, teaching short C++ design
and programming courses (mainly to professional programmers),
consulting about to introduction of and use of C++, discussing C++,
and generally thinking about programming, design, and C++.

 I don't know C or C++, should I learn C first?

No. Learn C++ first. The C subset of C++ is easier to learn for C/C++
novices and easier to use than C itself. The reason is that
C++ provides better guarantees than C (stronger type checking).
In addition, C++ provides many minor features, such as the `new'
operator, that are notationally more convenient and less error-prone
than their C alternatives. Thus, if you plan to learn C and C++ (or
just C++) you shouldn't take the detour through C. To use C well,
you need to know tricks and techniques that aren't anywhere near
as important or common in C++ as they are in C. Good C textbooks
tends (reasonably enough) to emphasize the techniques that you
will need for completing major projects in C. Good C++ textbooks,
on the other hand, emphasizes techniques and features that lead
to the use of C++ for data abstraction and object-oriented programming.
Knowing the C++ constructs, their (lower-level) C alternatives are
trivially learned (if necessary).

To show my inclinations:

 To learn C use:

  Kernighan and Ritchie:
  The C programming Language (2nd edition)
  Prentice Hall, 1988.

 as the primary textbook. To learn C++ use

  Stroustrup:
  The C++ programming Language (2nd edition)
  Addison Wesley, 1991.

Both books have the advantage of combining a tutorial presentation
of language features and techniques with a complete reference manual.
Both describes their respective languages rather than particular
implementations and neither attempts to describe particular libraries
shipped with particular implementations.

There are many other good textbooks and many other styles of
presentation, but these are my favorites for comprehension
of concepts and styles. It is always wise to look carefully
at at least two sources of information to compensate for bias
and possible shortcommings.



 I want to do OOP, should I learn Smalltalk before C++?

No. If you plan to use C++, learn C++. Languages such as C++, Smalltalk,
Simula, CLOS, Eiffel, etc., each has their own view of the key notions
of abstraction and inheritance and each support them in slightly different
ways to support different notions of design. Learning Smalltalk will
certainly teach you valuable lessons, but it will not teach you how to
write programs in C++. In fact, unless you have the time to learn and
digest both the Smalltalk and the C++ concepts and techniques, using
Smalltalk as a learning tool can lead to poor C++ designs.

Naturally, learning both C++ and Smalltalk so that you can draw from
a wider field of experience and examples is the ideal, but people
who haven't taken the time to digest all the new ideas often end up
``writing Smalltalk in C++'' that is applying Smalltalk design notions
that doesn't fit well in C++. This can be as sub-optimal writing C or
Fortran in C++.

One reason often quoted for learning Smalltalk is that it is ``pure''
and thus force people to think and program ``object oriented.''
I will not go into the discussion about ``purity'' beyond mentioning
that I think that a general purpose programming language ought to
and can support more than one programming style (``paradigm'').

The point here is that styles that are appropriate and well
supported in Smalltalk are not necessarily appropriate for C++.
In particular, a slavish following of Smalltalk style in C++
leads to inefficient, ugly, and hard to maintain C++ programs.
The reason is that good C++ requires design that takes advantage
of C++'s static type system rather than fights it. Smalltalk
support a dynamic type system (only) and that view translated
into C++ leads to extensive unsafe and ugly casting.

I consider most casts in C++ programs signs of poor design. Some
casts are essential, but most aren't. In my experience, old-time
C programmers using C++ and C++ programmers introduced to OOP
through Smalltalk are among the heaviest users of casts of the
kind that could have been avoided by more careful design.

In addition, Smalltalk encourages people to see inheritance as
the sole or at least primary way of organizing programs and to
organize classes into single-rooted hierarchies. In C++, classes
are types and inheritance is by no means the only means of organizing
programs. In particular, templates is the primary means for
representing container classes.

I am also deeply suspicious of arguments proclaiming the need to FORCE
people to write in an object-oriented style. People who don't want to
learn can, on average, not be taught with reasonable effort and there
is in my experience no shortage of people who DO want to learn. Unless
you manage to demonstrate the principle behind data abstraction and
object-oriented programming all you'll get is inappropriate ``barouque''
misuses of the language features that support these notions - in C++,
Smalltalk, or whatever.

See ``The C++ Programming (2nd Edition)'' and in particular Chapter 12
for a more thorough discussion of the relation between C++ language
features and design.



 Should I start using C++ as an OOPL or as a better C?

That depends. Why do you want to start using C++? The answer to that
question ought to determine the way you approach C++; not some
one-size-fits-all philosophy. In my experience the safest bet is
to learn C++ ``bottom up,'' that is first learn the features C++
provides for traditional procedural programming, the ``better C''
sub-set, then learn to use and appreciate the data abstraction features,
and then learn to use class hierarchies to organize sets of related
classes.

It is - in my opinion - dangerous to rush through the earlier stages
because there is too high a probability of missing some key point.

For example, an experience C programmer might consider the ``better
C'' subset of C ``well known'' and skip the 100 pages or so of a
textbook that describes it. However, in doing so he might miss the
ability to overload functions, the difference between initialization
and assignment, the use of the `new' operator for allocation, the
explanation of references, or some other minor feature in such a way
that it will come back to haunt him at a later stage where sufficient
new concepts are in play to complicate matters. If the concepts used
in the better C subset are known the 100 pages will only take a couple
of hours to learn and some details will be interesting and useful.
If not, the time spent is essential.

Some people have expressed fear that this ``gradual approach'' leads
people to write in C style forever. This is of course a possible
outcome, but nowhere as likely as proponents of ``pure'' languages
and proponents of the use of ``force'' in teaching programming like
to believe. The key thing to realize is that using C++ well as a
data abstraction and/or object-oriented language requires the
understanding of a few new concepts that have no direct counterpart
in languages such as C and Pascal.

C++ isn't just a new syntax for expressing the same old ideas -
at least not for most programmers. This implies a need for education,
rather than mere training. New concepts have to be learned and
mastered through practice. Old and well-tried habits of work have
to be re-evaluated, and rather than dashing of doing things ``the
good old way'' new ways have to be considered - and often doing
things a new way will be harder and more time-consuming than
the old way - when tried for the first time.

The overwhelming experience is that taking the time and making the
effort to learn the key data abstraction and object-oriented techniques
is worth while for almost all programmers and yields benefits not
just in the very long run but also on a three to twelve month timescale.
There are benefits in using C++ without making this effort, but most
benefits requires the extra effort to learn new concepts - I would
wonder why anyone not willing to make that effort would switch to C++.

When approaching C++ for the first time, or for the first time after
some time, take the time to read a good textbook or a few well chosen
articles (the C++ Report and the C++ Journal contain many). Maybe also
have a look at the definition or the source code of some major library
and consider the techniques and concepts used. This is also a good idea
for people who has used C++ for some time. Many could do with a review
of the concepts and techniques. Much has happened to C++ and its associated
programming and design techniques since C++ first appeared. A quick
comparison of the 1st and the 2nd edition of ``The C++ Programming
Language'' should convince anyone of that.



 How long does it take to learn C++?

Again, that depends. It depends both on your experience and on what
you mean by ``learning C++.'' The syntax and basics for writing C++
in the better C style plus defining and using a few simple classes
takes a week or two for a programmer. That's the easy part. The main
difficulty, and the main fun and gain comes from mastering new design
and programming techniques. Most experienced programmers I have talked
with quotes times from a half year to one and a half year for becomming
really comfortable with C++ and the key data abstraction and object-
oriented techniques it supports. That assumes that they learn on the
job and stay productive - usually by programming in a ``less adventurous''
style of C++ during that period. If one could devote full time to
learning C++ one would be comfortable faster, but without actual
application of the new ideas on real projects that degree of comfort
could be misleading. Object-oriented programming and object-oriented
design are essentially practical - rather then theoretical - disciplines.
Unapplied, or applied only to toy examples, these ideas can become
dangerous ``religions.''

Note that learning C++ is then primarily leaning programming and design
techniques, not language details. Having worked through a good textbook
I would suggest a book on design such as

  Grady Booch:
  Object Oriented Design with examples
  Benjamin Cummings 1990.

which has the nice property of having longish examples in five different
languages (Ada, CLOS, C++, Smalltalk, and Object Pascal) and is therefore
somewhat immune to the language biogotry that mar some design discussions.
The parts of the book I like best is the presentation the design concepts
and the example chapters.

Looking at design contrasts sharply with the approach of looking very
carefully at the details of the definition of C++ - usually using the ARM

  Ellist&Stroustrup:
  The Annotated C++ Reference Manual
  Addison-Wesley, 1990

which is a book containing much useful information, but no information
about how to write C++ programs. A focus on details can be very distracting
and lead to poor use of the language. You wouldn't try to learn a foreign
language from a dictionary and grammar, would you?

When learning C++, it is essential to keep the key design notions in mind
so that one doesn't get lost in the language technical details. That done,
learning and using C++ can be both fun and productive. A little C++ can
lead to significant benefits compared to C, further efforts to understand
data abstraction and object-oriented techniques yields further benefits.

 - Bjarne Stroustrup




Author: jln2@cec2.wustl.edu (Sammy D.)
Date: Mon, 13 Sep 1993 22:04:34 GMT
Raw View
Someone on the Net uses a signature that says (roughly) "flaming is the
only form af art native to the Internet".  I don't believe in
signatures myself, but I do indulge in using the Keywords headers to
indicate my tongue-in-cheek beliefs.  'Nuff said about that.

In article <26550@alice.att.com> bs@alice.att.com (Bjarne Stroustrup) writes:
---------------------------------------------------^^^^^^^^^^^^^^^^^

[If News supported MIME, I would insert a film clip of Wayne and Garth
falling to their knees while screaming "We're not worthy!"  Since it
doesn't you'll have to use your imagination.]

> > Why doesn't C++ give
> > us :before, :after, :and, :or and all the rest.  C++'s way of doing
> > inheritance is like doing structured programming in Fortran 66.

>Had I wanted to support dynamic inheritance, I would have done so. I knew
>enough Smalltalk, Flavors, and (more recently) CLOS to design a good
>imitation had I wanted one. I didn't. If I need a more dynamic system
>I know where to find Smalltalk or CLOS. There is (IMO) no need for an
>immitation; those languages serve their intended purposes well enough.

Actually, I wasn't even thinking about dynamic inheritance when I wrote
this.  (At least, I don't think I was.)  The person who started this
thread was expressing a desire for better structure in the C++
inheritance mechanism.  I tend to agree that better structure would be
A Good Thing.  The current technique (IMHO) tends to obscure how
methods relate to each other in the inheritance tree, and I think that
just as thirty-one flavors of looping statements are clearer than
rampant use of the goto, some form of saying up front how a method
relates to others with the same name is also good.  Right now, when I
code a constructor, I can say "child::child(...):parent(...){...}" and
get the effect of :before from Flavors.  If this be dynamic
inheritance, I'm guilty of advocating it.

>Unfortunately, flame wars are often so much more interesting than presenting
>simple explanations to the novices who needs them :-( Similarly, arguing
>subtleties with language lawyers seems to have a perverse attraction.

I'm often guilty of this.  8-)

> > This makes the third time in as many years I've looked hard at C++,
> > and my decisions are always the same.

>It sounds like you dislike or doesn't need static structure and/or static
>type checking. If so, your decision is probably correct. Fake the dynamic
>inheritance mechanisms in C (or the C subset of C++), or even better use
>a language designed to support your style.

>One might also suspect that you haven't looked very hard and maybe in the
>wrong places:

I am very knowledgable about Turbo Pascal with OOP extensions.  I don't
know how this dialect relates to Objective Pascal, but I like it a
lot.  Borland has frequently and loudly pointed out that their OOP
extensions are derived from and compatible with C++, to the point that
you can link routines from each together.  This makes it hard for _me_
to understand just why _I_ don't like C++ nearly as much, especially
since I like C a lot more than Pascal.  Part of my original flame is an
attempt by me to understand this part of myself better.  This lack of
self-knowledge is part of the reason why I say "Opinions expressed are
not necessarily my own!"

>I don't think you can learn C++ in a week. At least, I know that most good
>programmers can't learn C++ in a week. That is, actually, one thing people
>keep remarking on as a GOOD thing. You don't exhaust the language in a
>week or a month but continue to learn new things and gain concrete benefits
>from new techniques and concepts month after month.

> > Actually, my C++ knowlege stinks.  I looked at a few years ago when
> > Borland first offered their C++ compiler, dropped it, tried it again
> > about a week ago and have decided to drop it again.

I have replied to a question on why "new char[0]" returns a pointer other
than NULL with an answer that in part related to the C malloc function
and why it does the same.  The questioner complemented me on my in-depth
knowledge of C++.  (I quickly demurred.)

> > one of my pet peeves is that it is apparently impossible to directly
> > cast a va_list into a (char**) to pass to execv...

>If that (whatever it is) is impossible in C++ it is equally impossible in C.
>It sounds to me like a confusion about how C (and maybe therefore C++) works.

> > Simultaneously, other C++ promoters will argue that C++ generates code
> > just a efficient as C.

>Equivalent code is at least as efficient. Non-equivalent code can be more
>or less efficient dependent on exactly how it is non-equivalent.

In this instance (and I hate to get bogged down discussing individual
trees when I want to discuss the forest), <stdarg.h> defines the type
va_list very opaquely.  I have a routine (such as execv) that will accept
a char** argument.  In C, I can say (char**)whatever and pass the pointer
along.  C++ complains.  Loudly.  The best suggestion I've seen is write
a loop and cast each pointer one at a time.  This is _not_ as efficient
as a single cast.

>For many, this ``fun'' comes from being able to express ideas more
>clearly, from being able to learn new concepts and techniques and
>apply them, from being relieved from some of the more tedious aspects
>of C and Pascal programming, and from a feeling of doing a better job.

I will admit that perhaps I haven't had the "A-Ha!" flash of insight
needed to understand what C++ is all about, but so far, my attempts to
apply the new concepts and techniques have been more tedious, not less.

>The question to ask the net is not ``What good is C++ in general?'' but
>``what good is C++ relative to my particular needs?'' The former question
>can only be answered by generalities (usually somewhat vague), the latter
>can be answered by concrete arguments and examples, and can usually be
>backed up with references to the extensive literature about C++ and its
>use.

>So if you want to learn C++, first figure out why C++ might help you.
>Trying to learn C++ just because ``everybody uses in'' (not everybody
>does use C++ and not should use C++) or because someone promised you
>that ``it performs miracles'' (it doesn't) is silly. Unless you have
>a pretty good idea of what you want and how you are going to achieve
>it you'll most likely fail - in any language.

I am as guilty as anyone at running with the "in-crowd" be it the fall
fashions or the hottest new programming language.  The most recent
trial of C++ by myself involved a TCP/IP server that would accept
connections from a variety of similar but not identical clients.  I
thought that C++ would be a good way to encapsulate the similarities of
the clients while accentuating the differences.  I tried to code a toy
version and found the type-checking was continously getting in my way.
Again, perhaps I've just missed the "A-Ha!" in designing C++ systems.
Or, perhaps C++ is of little good relative to my particular needs.  In
this case, I need to get the product out the door, so I've gone back
to C.

ANSI has "stolen" function prototyping from C++ and this is, IMHO, a
Good Thing.  I really wish that they would "steal" some other features
("struct newstruct : oldstruct {...}" would be at the top of my list),
although I fear that it would be like plucking a thread from a coat.
I would really like to use the C subset of C++, but methinks that is
like using a subset of PL/I:  Just because you try to ignore the
other parts of a language doesn't mean that they won't bite you when
you aren't looking.

Thank you, Bjarne, for taking the time to reply to my flame.  You
obviously put a lot time into composing your reply and I appreciate
it.  This reply of mine is intended to clear up just those parts of my
original posting that I rendered unclear in my haste.  Although I
tend toward hyperbole, I try to be constructive in my flames and
explain why I think something and not just say "XYZ stinks!"




Author: rfb@lehman.com (Rick Busdiecker)
Date: Tue, 14 Sep 1993 12:05:43 GMT
Raw View
In article <26550@alice.att.com> bs@alice.att.com (Bjarne Stroustrup) writes:

   Had I wanted to support dynamic inheritance, I would have done so. I knew
   enough Smalltalk, Flavors, and (more recently) CLOS to design a good
   imitation had I wanted one. I didn't. If I need a more dynamic system
   I know where to find Smalltalk or CLOS. There is (IMO) no need for an
   immitation; those languages serve their intended purposes well enough.

I think that most people can agree that C++ is not simply an
alternative syntax for gaining access to all of the features that
other OO languages provide.  It was not designed to meet that goal.  I
think that there are a lot of ways to view C++ and to some extent I
think that the issue of object-orientedness it's pretty irrelevant.
What's in a name?

I wrote my first C++ program in 1986 and the way that I chose to view
C++ was essentially the ``better C'' view.  Basically, the big feature
of C++ in my mind was that you could do `real' modular abstraction.  I
have been very happy to see additional features added to C++ and was
especially happy when C++ took the multiple-inheritance plunge
. . . except for a single, in my mind very glaring, intentional
omission: it has no method combination mechanism for user methods.
Please note that I don't really want anything more than what already
exists for constructors and destructors.  I simply want *some* form of
method combination to preserve what I saw as the big advantage of C++
over C.

The ARM discusses this issue on and arround page 201.  It provides an
example of how to achieve method combination in C++.  That example
demonstrates that to derive a class from two other classes, you must
know the detail of the entire inheritance hierarchy.  If anything
changes, all code related to method combination must change.

I believe that this is a major cop-out.  Clearly the problem has been
addressed by the language.  Constructors and destructors must be
called exactly once for each node in the class lattice.  The problem
is simply that no mechanism has been provided for user defined
methods.

In the ARM, on page 202, this text appears:

  ``Additional support for programming using multiple inheritance,
    such as the method combination schemes in some Lisp dialects, was
    considered.  None of the alternatives considered, however, seemed
    simple, general, and efficient enough to justify the complexity
    they would add to C++.  In particular, it was not obvious how to
    combine the C++ strong static typ checking with a scheme flexible
    enough to support directly the ``mix-in'' style of programming
    used in some Lisp dialects.''

This sounds like a lot of hand-waving and resembles the flavor of
argument in the excerpted paragraph at the beginning of this article.
``Solving this would mean C++ would be like Lisp'' is what seems to be
implied.  I've done a lot of CLOS hacking.  I like CLOS a lot.  I
don't think that C++ needs all of the features of CLOS to be a great
language.  I don't think that allowing user methods to have access to
the same functionality that is already provided for special member
function would necessitate added complexity.  I *do* think that the
approach to method combination proposed in the ARM violates the basics
of modular programming and clean abstraction.

In fact, while I would very happily settle for much less, I think that
one could certainly imagine something that closely resembled CLOS
default method combination with a totally static definition.  That is,
virtual functions are permitted to invoke call_next_method which is
special form defined to take the same arguments and return the same
result type as the current member function and it calls the next
applicable method as defined by the class lattice.  I'd like to point
out that achieving method combination in this form has the following
properties:
 - It's static: The `next method' is completely determined at
   compilation time.
 - The additional language complexity is one identifier:
   call_next_method.
 - If you don't use it, you don't pay for it.
 - the default ordering for method combination -- the one used in the
   ARM example and in CLOS default method combination -- is applicable
   to a wide variety of situations.
 - Something extremely similar is already built into C++.

However, if compiler builders outside of the Lisp world can't handle
this :-), a more limited form of method combination could go a long
way toward eliminating the current necessity of abandoning modularity
in order to achieve method combination.

The simplest mechanism might be to added a `combined' keyword that
that would do nothing more than ensure that every applicable method
was invoked exactly once for a call to the member function.  No
guarantee as to any particular order.  The member function and all of
it's methods might be required to have identical parameters and void
return type.

Improvements to levels of support between this very simplistic
approach and something like CLOS default method combination might
include:
1. defining an ordering, such as the one used in the example
   spanning pages 201-202.
2. defining a suppress_combination declaration or call which would
   prevent subsequent methods from being invoked.

I must admit that I did was not involved in the previous discussions
related to method combination, however from what I've seen, nothing
very substantial has been put forward to suggest that something like
call_next_method should not be added to the language.  Is the case
against it based completely on difficulty for compiler writers or is
there something more?
--
Rick Busdiecker <rfb@lehman.com> and <rfb@cmu.edu>
  Lehman Brothers
  3 World Financial Center ``I never did give anybody hell.  I just told
  New York, NY 10285-0900   the truth and they thought it was hell.
  (212) 640-9419       - Harry S. Truman




Author: schmidt@liege.ics.uci.edu (Douglas C. Schmidt)
Date: 14 Sep 1993 11:09:41 -0700
Raw View
In article <1993Sep13.220434.29456@wuecl.wustl.edu>,
Sammy D. <jln2@cec2.wustl.edu> wrote:
++ The most recent
++ trial of C++ by myself involved a TCP/IP server that would accept
++ connections from a variety of similar but not identical clients.  I
++ thought that C++ would be a good way to encapsulate the similarities of
++ the clients while accentuating the differences.  I tried to code a toy
++ version and found the type-checking was continously getting in my way.

 If I understand the requirements of your TCP/IP server
correctly, you might want to check out the ADAPTIVE Communication
Environment (ACE) C++ wrappers library available via anonymous ftp
from ics.uci.edu (128.195.1.1) in the file gnu/C++_wrappers.tar.Z.
The ACE library contains an integrated suite of C++ classes that
handle local and remote IPC, I/O-based and timer-based event
multiplexing, explicit dynamic linking, and multi-threading.

 Once you ftp the release, please check out an example in the
./test/Logger subdirectory that roughly corresponds to what you
describe above.  The general idea is to have two template classes:

 1. Handle_Connection_Requests
 2. Handle_Data_Transfer

both of which are parameterized by the type of IPC facility that you
want to use (the ACE library provides several choices, based upon
sockets, TLI, or STREAM pipes).  Moreover, both of these classes are
inherited from an Event_Handler facility that interoperates with the
Reactor (which is an object-oriented event demultiplexor that operates
atop either select() or poll()).

 The current example is a distributed logging facility that
implements *homogeneous* Data_Transfer functionality (which doesn't
exactly meet the requirements you outlined above).  However, it
wouldn't be difficult to further parameterize the Handle_Data_Transfer
class with a pointer to a function that would provide the
heterogeneous behavior that you describe above.  Furthermore, if you
don't like this approach, you can always add a pure virtual function
called something like "perform_client_service()" that can be
overridden on a per-subclass basis (see chapter 8 of Rob Murray's "C++
Strategies and Tactics" for more details on the alternative approaches
here).

 The main point of all this is that C++ provides a wide range
of features that, when combined with advanced OS mechanisms such as
explicit dynamic linking and multi-threading, enable the development
of extremely flexible, extensible, efficient, and type-secure network
applications.

 If you are interested in more details on applying C++ and OO
to network programming, you might check out the following articles
that have appeared in recent issues of the C++ Report magazine:

----------------------------------------
 Sept/Oct '92: "Systems Programming with C++ Wrappers: Encapsulating
  Interprocess Communication Services with
  Object-Oriented Interfaces"

 Nov/Dec '92 "IPC_SAP: An Object-Oriented Interface to
  Interprocess Communication Services"

 Feb '93 "The Reactor: An Object-Oriented Interface for
  Event-Driven UNIX I/O Multiplexing (Part 1 of 2)"

 Sept '93 "The Object-Oriented Design and Implementation of the
  Reactor: A C++ Wrapper for UNIX I/O Multiplexing (Part
  2 of 2)"
----------------------------------------

 Likewise, you might want to attend my tutorial on
"Object-Oriented Network Programming" at the upcoming C++ World
conference in Dallas in October ;-)

 Doug

----------------------------------------
p.s. Here's the README file from the ACE library, if anyone is
     interested in more info:

THE "ADAPTIVE COMMUNICATION ENVIRONMENT" (ACE) C++ WRAPPER LIBRARY

 The ACE library is available for anonymous ftp from the
ics.uci.edu (128.195.1.1) host in the gnu/C++_wrappers.tar.Z file
(approximately 1.3 meg compressed).  This release contains contains
the source code, documentation, and example test drivers for a number
of C++ wrapper libraries developed as part of the ADAPTIVE transport
system project at the University of Calfornia, Irvine.  These wrappers
encapsulate many of the user-level BSD and System V Release 4 IPC
facilities such as sockets, TLI, select and poll, named pipes and
STREAM pipes, the mmap family of memory-mapped file commands, System V
IPC (i.e., shared memory, semaphores, message queues), and explicit
dynamic linking (e.g., dlopen/dlsym/dlclose) using type-secure,
object-oriented interfaces.

 Several of these wrappers have been described in recent issues
of the C++ Report and in the proceedings of the 1993 C++ World
conference held in Dallas, Texas in October.  A relatively complete
set of documentation and extensive examples are included in the
release.

CONTENTS OF THE RELEASE

 The following subdirectories are included in this release:

 . bin   -- utility programs for building this release such as g++dep
 . build   -- a separate subdirectory that keeps links into the main
       source tree in order to facilitate multi-platform
       build-schemes
 . doc   -- LaTeX documentation (in both latex and .ps format)
 . include -- symbolic links to the include files for the release
 . lib   -- object archive libraries for each C++ wrapper library
 . papers  -- subdirectories with the latest versions of the C++ Report
       and C++ World conference papers
 . libsrc  -- the source code for the following C++ wrappers:
   Get_Opt -- a C++ version of the UNIX getopt utility
   IPC_SAP -- wrapper for BSD sockets
   IPC_SAP_FIFO -- wrapper for FIFOS (named pipes)
   IPC_SAP_SPIPE -- wrapper for SVR4 STREAM pipes and connld
   Log_Msg -- library API for a local/remote logging facility
   Mem_Map -- wrapper for BSD mmap() memory mapped files
   Message_Queues -- wrapper for SysV message queues
   Reactor -- wrapper for select() and poll()
   Semaphores -- wrapper for SysV semaphores
   Server_Daemon -- a wrapper for dynamically linking
   Shared_Memory -- wrapper for SysV shared memory
   Shared_Malloc -- wrapper for SysV/BSD shared mallocs
   TLI_SAP -- wrapper for SVR4 TLI
 . tests -- programs that illustrate how to use the various wrappers

 Please refer to the INSTALL file for information on how to
build and test the ACE wrappers.  The BIBLIOGRAPHY file contains
information on where to obtain articles that describe the ACE wrappers
and the ADAPTIVE system in more detail.

COPYRIGHT INFORMATION

 You are free to do anything you like with this code.  However,
you may not do anything to this code that will prevent it from being
distributed freely in its original form (such as copyrighting it,
etc.).  Moreover, if you have any improvements, suggestions, and or
comments, I'd like to hear about it!  It would be great to see this
distributed evolve into a comprehensive, robust, and well-documented
C++ class library that would be freely available to everyone.
Natually, I am not responsible for any problems caused by using these
C++ wrappers.

 Thanks,

  Douglas C. Schmidt
  Department of Information and Computer Science
  University of California, Irvine
  Irvine, CA 92717
  Work #: (714) 856-4105
  FAX #: (714) 856-4056

ACKNOWLEDGEMENTS

 Special thanks to Paul Stephenson for devising the recursive
Makefile scheme that underlies this distribution.

--
His life was gentle, and the elements so            | Douglas C. Schmidt
Mixed in him that nature might stand up             | schmidt@ics.uci.edu
And say to all the world: "This was a man."         | ucivax!schmidt
   -- In loving memory of Terry Williams (1971-1991)| (714) 856-4101




Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 14 Sep 93 20:22:30 GMT
Raw View

Rick Busdiecker <rfb@lehman.com> writes

 > ... except for a single, in my mind very glaring, intentional
 > omission: it has no method combination mechanism for user methods.
 > ...
 > The ARM discusses this issue on and arround page 201.
 > ...
 > I believe that this is a major cop-out.
 > ...
 > This sounds like a lot of hand-waving ...
 > I *do* think that the
 > approach to method combination proposed in the ARM violates the basics
 > of modular programming and clean abstraction.
 > ...
 > In fact, while I would very happily settle for much less,
 > ...
 > what I've seen, nothing
 > very substantial has been put forward to suggest that something like
 > call_next_method should not be added to the language.  Is the case
 > against it based completely on difficulty for compiler writers or is
 > there something more?

I have been down this road before. One reason for the ``hand waving'' is that
if I gave lengthy discussions of every feature someone had considered essential
for C++ my writings would be MUCH larger yet. Other parts of C++ and/or its
documentation would also suffer.

In this particular case, nothing is going to happen unless someone comes up
with a concrete, detailed, and well motivated proposal. I have over the years
heard many suggestions for method combination but none were concrete and
detailed. Worse none were supported by motivation significantly beyond
``I like it.'' Well, so do I. In fact, C with Classes had the equivalent
to :before and :after methods. However, no-one but me used them so they
didn't make it into C++.

I don't see implementation problems as a major obstacle to method combination.
I don't see a specific proposal either. Many of the vague suggestions I have
heard violate the general ideas of static checking of C++ programs. Many of
the ideas that don't get into trouble with static checking support only a
sub-set of what various multi-method proponents have suggested; it would
therefore be harder to argue for their generality and  their usefulness.
Finally, if there was a well-specified and well-motivated proposal we'd
have to consider if IT of all possible extensions deserved to be considered.
Each time I have reviewed the issue the amount of work needed to produce
and evaluate a language feature supporting method combination seemed large
for the likely benefits.

Much of this apply to extension ideas in general.

Designing and evaluating a feature is a lot of work. For example, see
``How to Write a C++ Language Extension Proposal'' The C++ Report May 1992.
Also, ACM Sigplan Notices, Vol 27 No 6 June 1992 .

The issue is not that

 > nothing
 > very substantial has been put forward to suggest that something like
 > call_next_method should not be added to the language.

it is that

 nothing very substantial has been put forward to suggest that
 something like method combination should be added to the language.

The default is that a new feature is NOT added to the language, the
burden of ``proof'' is on the person who wants the change. Stability of
the language definition is a virtue so any extension must be evaluated
in light of the fact that even a perfect extension has undesirable
sideeffects. See ``Why Consider Language Extensions?'' The C++ Report,
September 1993 (this month's issue).

 - Bjarne




Author: daveg@synaptics.com (Dave Gillespie)
Date: 15 Sep 93 10:11:09 GMT
Raw View
rfb@lehman.com (Rick Busdiecker) writes:
> In fact, while I would very happily settle for much less, I think that
> one could certainly imagine something that closely resembled CLOS
> default method combination with a totally static definition.  That is,
> virtual functions are permitted to invoke call_next_method which is
> special form defined to take the same arguments and return the same
> result type as the current member function and it calls the next
> applicable method as defined by the class lattice.

Let me see if I understand your proposal correctly:

  class A defines a member foo
  class B inherits from A and defines a member foo

Following the CLOS model, both "foo"s would include calls to
"call_next_method"; A's call does nothing, and B's call calls
"A::foo".  All of this can be statically determined.

But what about return values?  Unless member "foo" returns void,
you're faced with the question of what "call_next_method" in A
should return.  In real CLOS, "call_next_method" is an error
in A, but since things are dynamic it's a run-time error, not
a compile-time error.  "A::foo" can use "next_method_p" to decide
whether it's safe to call "call_next_method".  This is less
clear-cut in static C++, where the obvious arrangement would be
to have "call_next_method" be a *compile-time* error in A.

I guess there's nothing stopping "call_next_method" from being a
run-time error in A, except for being somewhat out of character
for C++.  But you'd need a second "next_method_p" built-in
function then.  A variant would be to say that "call_next_method"
does nothing but returns an "undefined" value.  This would make
things simple and precise when the method returns void, certainly
a common and useful case.

Or, "call_next_method" could be a compile-time error in A, and
the programmer would have to know whether or not it's safe to
call it based on prior knowledge of the inheritance graph.  But
the whole point was to eliminate the need for such prior
knowledge!

Okay, so what about *multiple* inheritance?  Here, the most
basic pattern is:

  class A defines a member foo
  class B defines a member foo
  class C inherits from A and B and defines a member foo

What does "call_next_method" do in "C::foo"?  By the CLOS
model, it ought to call "A::foo", whose "call_next_method"
would in turn call "B::foo".  But note that for an actual
A object, "A::foo"'s supposedly static "call_next_method"
would be an error or no-op.  So either things are not as
static as they first seem, or "A::foo" actually means
different things in different circumstances.

Note that a method in CLOS is *not* a function.  Methods are
pseudo-functions that have bodies and arglists but are only
called when they are wrapped up as part of some generic
function.  An efficient implementation of CLOS probably does
one of two things:  Either (a) the complete generic function
includes inline copies of each inherited method, linked
together statically, or (b) the methods are compiled just
like ordinary functions but with an extra "next_method_list"
hidden parameter of some sort.

Option (a) is not suitable for C++ because inlining isn't
always possible, e.g., if the various methods come from
different source files.

Option (b) is more plausible; the method list to be passed
into "next_method_list" could be a statically generated,
NULL-terminated array of member function pointers.  But that
has to be passed in somehow, and you have to make a distinction
between member functions which correspond to generic functions,
and member functions which correspond to methods.  When the
user calls "C::foo", s/he is calling the generic function,
but when it in turn calls "A::foo", it is calling the method
of the same name.  A closer reading of the example on page
202 of the ARM shows this very distinction:  Every class has
both a generic function "f" and a corresponding method "_f".
The user calls "f", but the "f"'s call "_f"'s to do the real
work.  The net result is that every member function call
turns into a double function call, since every member function
has to be implemented as a method plus a generic function just
in case that member function is used by "call_next_method" in
some subsequent derived class.  Sadly, this is a major new
overhead which everybody would have to pay for even if they
don't use method combination, barring some rather subtle
optimizations in the compiler.

There's another possibility, where we get rid of the distinction
between methods and generic functions and just have plain old
fully static-compiled member functions as before.  Now, since
"C::foo"'s "call_next_method" has to result in calls to both
"A::foo" and "B::foo", neither of which calls the other, we're
left with "C::foo"'s "call_next_method" expanding directly into
calls to both methods in sequence.  But this has two serious
flaws.

First, if A and B themselves both inherit from W, as in the
ARM example, then the above recipe will cause "W::foo" to be
called twice, once from inside "A::foo" and again from inside
"B::foo".  Note that the ARM example avoids this only because
it has separate methods and generic functions.

Second, the situation with return values is now hopeless.
What does "call_next_method" return now, since it's expanding
to two different calls?  Picking one return value to pass
back and dropping the other seems awfully arbitrary, but no
other option seems better.  The sorts of choices that would
make for a solid and robust definition in the presence of
multiple inheritance, would be unduly cripping in the single
inheritance case.

> I believe that this is a major cop-out.  Clearly the problem has been
> addressed by the language.  Constructors and destructors must be
> called exactly once for each node in the class lattice.

The difference is that constructors and destructors are very
special, limited things.  Calls to them are very stylized and
are usually implicit; they do not have return values.  They are
much simpler than the general case of arbitrary member functions.

> The simplest mechanism might be to added a `combined' keyword that
> that would do nothing more than ensure that every applicable method
> was invoked exactly once for a call to the member function.

Bjarne Stroustup mentioned that, while C++ never had a general
form of method combination, it did early on have the analogue
of C++'s :before and :after methods.  I can't think of any
reason why these could not be reintroduced into the language.
Such member functions would still have to involve both methods
and generic functions, but their presence would not force *all*
member functions to be split in two.  I'm too tired now to work
out the consequences of multiple inheritance, but I'll bet they
would only be medium-hairy.

Before/after methods would let you simulate your `combined'
notation, plus a bunch of other useful idioms.

        -- Dave
--
Dave Gillespie
  daveg@synaptics.com, uunet!synaptx!daveg




Author: jacob@sun19.objy.com (Jacob Butcher)
Date: Wed, 15 Sep 93 22:03:43 GMT
Raw View
rfb@lehman.com (Rick Busdiecker) writes:
>In fact, while I would very happily settle for much less, I think that
>one could certainly imagine something that closely resembled CLOS
>default method combination with a totally static definition.  That is,
>virtual functions are permitted to invoke call_next_method which is
>special form defined to take the same arguments and return the same
>result type as the current member function and it calls the next
>applicable method as defined by the class lattice.  I'd like to point
>out that achieving method combination in this form has the following
>properties:
> - It's static: The `next method' is completely determined at
>   compilation time.
> - The additional language complexity is one identifier:
>   call_next_method.
> - If you don't use it, you don't pay for it.
> - the default ordering for method combination -- the one used in the
>   ARM example and in CLOS default method combination -- is applicable
>   to a wide variety of situations.
> - Something extremely similar is already built into C++.

First of all, I completely agree with Rick that the lack of abstract
mechanisms for method combination in C++ is a real pain.  Essentially, any
code that must express method combinations, whether in a virtual,
constructor, or regular method, depends on the inheritence hierarchy.  (OK,
you knew that.  I'm being pedantic.)  This is unfortunate, and I'd like to
see it fixed.  Rick's solution is not completely general, but it captures
the important common cases, and its value has already been demonstrated in
CLOS and other languages.  Of course, it does beg the question of how you
can use call_next_method as a value, what its type is, and how to handle
multiple inheritance, but I think those questions can be nailed down with a
little thought.  Whether the solution is still worth using once nailed down,
well, comments welcome.

However, I do not agree with Rick's analysis.  The main problem is the
argument that constructors already provide the ability to specify method
combinations.  In fact, the only way to combine constructors is to specify
the arguments to the base classes, which must be explicitly named.  You
have no control over the arguments to your base classes' base classes, nor
the order in which the various constructors are called.  Not only is this
not more general that the existing technique for combining methods, it is
less general, since when combining methods you can combine *any* inherited
method implementations, and in any order, although you must still explicitly
name them.  So in fact, while I still think call_next_method handles common
cases nicely, it does not solve the problem for constructors nor does it
provide all the flexibility for method combination sometimes required.

While we're near the topic, does anyone else but me loathe the fact that
"::" qualification is a simple scope specification mechanism nearly all the
time, but suddenly when you use it on a virtual function it actually
changes the semantics of function call invocation?  One nice feature of
Rick's solution is that it might pave the way toward eliminating this
little "gotcha".

    Jacob Butcher

PS: Actually, "call_next_method" is probably not a good name, since the method
is neither necessarily called nor next.  Perhaps "inherited_method"?




Author: jln2@cec2.wustl.edu (Sammy D.)
Date: Sun, 12 Sep 1993 00:08:14 GMT
Raw View
In article <CD66Gw.9n3@plato.ds.boeing.com> dano@dogfish.ds.boeing.com (Dan Olson) writes:
>Historical Info (for anybody who cares):
>
>For a variety of ways that virtual functions could be called, find
>your old dusty Symbolics Lisp manual and read about Flavors method
>combinations.  Flavors provided numerous ways of having methods
>override each other having such things as :before and :after methods
>(i.e. all functions defined :before get called before the "main"
>function) and ":and" and ":or" method combinations so all overriding
>functions get called until one returns nil (:and) or t (:or).  And
>don't forget the whoppers and wrappers!  Actually these were all
>constructs that made multiple inheritance a little more powerful than
>it is in C++.
>
>Of course, these all can be done with C++ with a little control code.

Gee, Dano, you seem to have left your smiley off that last statement.

I learned OOP from Flavors, I knew OOP well, and believe me, C++ is not
an OOP language  (apologies to Senator Benson).  Why doesn't C++ give
us :before, :after, :and, :or and all the rest.  C++'s way of doing
inheritance is like doing structured programming in Fortran 66.  I
started listening in on comp.{lang,std}.C++ a week ago, because I
thought that C++ could help me with a project I was reengineering.  I'm
still listening, but I've decided to recommend staying with C.  This
makes the third time in as many years I've looked hard at C++, and my
decisions are always the same.

What don't I like?  Well, besides the preceeding, look at any of the
"how many angels on the head of a pin" arguments going on in
comp.std.c++ (matching argument lists to overloaded functions seems to
be particularly hot right now).  Look that the presumably experienced
programmers asking "why can't I do X, Y, or Z?" and getting told that a
page of arcane code will fix their problem (one of my pet peeves is
that it is apparently impossible to directly cast a va_list into a
(char**) to pass to execv, but scores of similar examples abound).
Simultaneously, other C++ promoters will argue that C++ generates code
just a efficient as C.

By the time you track down the right virtual function for your class,
you might as well have been doing everything in an interpreter (and
Forth techniques have made interpreters pretty damn quick these days).
The only thing C++ seems to do at all well, is integrate to GUIs.  Hey
guys, don't look now, but HyperCard, Visual Basic, Ingress` Windows
4GL, etc, all integrate to GUIs even better, they code easier, the
stuff you develope today can be _easily_ recycled into a new project
tommorrow, and the code is orders of magnitude easier to comprehend.




Author: peju@alice.att.com (Peter Juhl)
Date: 12 Sep 93 12:38:49 GMT
Raw View

jln2@cec2.wustl.edu (Sammy D.) writes:

>I learned OOP from Flavors, I knew OOP well, and believe me, C++ is not
>an OOP language  (apologies to Senator Benson).

I learned foreign languages from German, I know German well, and believe
me, English is not German.

To strengthen my case I'll add that I also learned French, believe me,
English is not French.

--- peter (peju@research.att.com)