[comp.lang.c++] Philosophy in designing C++

nevin1@ihlpb.ATT.COM (Liber) (12/22/88)

In article <424@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes:

>The comment I have delayed is that in C++ there often are no concise and
>thoughtful answers to wonderfully obscure questions. Usually there are no
>answers at all, because Bijarne Stroustrup did not bother with a lot of
>detail, and in the process of evolving the language, he hasn't given much
>time to clarification. To him C++ is still much of an experimental language.

Or maybe he hasn't clarified some of the "dark corners" of C++ because
making the wrong decision would impact the language in a negative way.
From what I have read of Bjarne's papers, all of his decisions are
accompanied by detailed explanations of how he arrived at his
conclusions, as well as pointing out the problems with the other
possible solutions.  This is a far better method of design than just
arbitrarily deciding how things should be.

>As Michael Tiemann has written, if only somebody cared to define exactly what
>the rules are in so many cases (especially visibility), many surprises would
>be spared even to the wary, and many small incompatibilities between cfront
>and g++ would not exist.

I not only care to have those cases defined, but I also care to have
them defined so that that they are consistent with the rest of the
language!  I want the definitions to make sense!  I feel that it is
much, much more important to wait until those decisions can be reasoned
out, than to have those decisions made prematurely, thereby hindering
the language forever.  It is much harder to take something out of the
language once people have written code dependent on it than it is to
add a definition when a reasonable choice can be made on what that
definition should be.

>In general, I like the choices Tiemann has made to resolve ambiguities.  I
>like them better than those apparent from cfront 1.2 behaviour.

The folks at GNU seem to be resolving ambiguities by deciding what is
better for the *compiler*, and not what is (necessarily) better for the
*language* (as evidence, I point to the recent discussion on why G++
uses an LALR(1) grammar, instead of using the language defined by the
C++ book).  Designing a language is very different process than designing
a compiler for a language.  Defining the language based on how you want
to write the compiler tends to lead to trouble.  One of the faults of C
is that it was designed to compile down to PDP-11 assembler (ex: in K&R-1
C compilers all floating point numbers are promoted to doubles for
the purposes of doing calculations).  It may help in the short term,
but in the long term the language tends to suffer.

Note:  studying cfront behavior is not the way to resolve the
ambiguities, either.  Try to use only the constructs which have
well-documented interpretations, and be prepared to someday rewrite code
that is strictly dependent on how your compiler does things.



Waiting a short while is a small price to pay in order to get a nice,
usable, consistent language.  It beats the alternative of making rash,
arbitrary, short-term decisions.
-- 
NEVIN ":-)" LIBER  AT&T Bell Laboratories  nevin1@ihlpb.ATT.COM  (312) 979-4751

pcg@aber-cs.UUCP (Piercarlo Grandi) (12/24/88)

In article <9247@ihlpb.ATT.COM> nevin1@ihlpb.UUCP (55528-Liber,N.J.) writes:

# It is much harder to take something out of the language once people have
# written code dependent on it than it is to add a definition when a
# reasonable choice can be made on what that definition should be.

Yes, I agree. I *did* say that C++ is still very much an experimental
language.  Unfortunately a lot of people are using it (within AT&T as well)
as a production language (me too shortly :->). This is very valuable
experience, of course, but probably somebody will be in for some suprise
sooner or later...

On the other hand in some case BS *could* have clarified a little better his
thoughts, or at least given a range of directions.

# The folks at GNU seem to be resolving ambiguities by deciding what is
# better for the *compiler*, and not what is (necessarily) better for the
# *language*

I agree on this, but with one obvious qualification: it often turns out that
not only simplicity of implementation is an important pragamatic
consideration, but it also is often true that design features that afford a
simple implementation are also the most elegant for a language.

# (as evidence, I point to the recent discussion on why G++ uses an LALR(1)
# grammar, instead of using the language defined by the C++ book).

Good evidence. In part however this reinforces my previous paragraph:  their
arguments that BS could have paid a little more attention to making parsing
easy are in my opinion well founded; maybe I am assuming too much, but it has
been my impression that the syntax "problems" are result of oversight; after
all it is fairly hard to anticipate all possible consequences of rules in the
design of a language.

While I have not given much thought to the issue, I don't see much to lose in
slightly changing syntax in the hard spots for the benefit of a parser, like
a LALR parser.

# Designing a language is very different process than designing a compiler
# for a language.  Defining the language based on how you want to write the
# compiler tends to lead to trouble.

A cautionary note: I agree that you want to DEFINE the language so that it is
independent of any particular implementation, but the DESIGN had better take
into account the possible implementations. One example: C++ was designed not
to require a runtime implementation substantially more complex than that for
C, nor a compiler substantially smarter. Other example: Algol68, while
beautifully designed, was not designed for ease of compilation or
implementation, and this is surely one of the factors that hampered it.

# One of the faults of C is that it was designed to compile down to PDP-11
# assembler

Probably a mixed blessing: on one hand it caused some funny PDP-11 dependent
quirks, on the other hand the PDP-11 model turned out to be an eminently simple
and proper one, that could be easily mapped to many other architectures.

Now, think what would have happened had they used an 8086 as a base.... :->

# (ex: in K&R-1 C compilers all floating point numbers are promoted to
# doubles for the purposes of doing calculations).

Even the floating point quirk can be reinterpreted in hindsight as a way to
ensure that the compiler was simpler and maximum precision always maintained
by insisting that all arithmetic be performed in double, while allowing space
to be conserved by permitting a short float format.

# It may help in the short term, but in the long term the language tends to
# suffer.

# Note:  studying cfront behavior is not the way to resolve the
# ambiguities, either.  Try to use only the constructs which have
# well-documented interpretations, and be prepared to someday rewrite code
# that is strictly dependent on how your compiler does things.

Agreed 100%.

# Waiting a short while is a small price to pay in order to get a nice,
# usable, consistent language.  It beats the alternative of making rash,
# arbitrary, short-term decisions.

I agree on this. Stroustrup has done a fairly good job, even if the language
is quite complex.

CONLUSION

While you agree with the idea that indeed in C++ there are no answers (yet)
to some good questions, I think that (provided that it is recognized that
some of these dark spots may be simply the result of quite understandable
oversights) you are quite right to point out that this may be a good thing,
to avoid early committment to not (yet) well understood solutions.

On  the issue of C++ complexity, I'd like to discuss a good question:  is this
complexity inherent in the desired level of functionality for C++ or could
the design have been simpler?

I used to think the answer was "it could have been simpler", both as to
functionality and the way to express it. I am no longer so sure... Anybody
cares to comment on what could have been made more orthogonal or omitted as
redundant?
-- 
Piercarlo "Peter" Grandi			INET: pcg@cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science	UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)

nevin1@ihlpb.ATT.COM (Liber) (12/28/88)

In article <466@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes:
|On the other hand in some case BS *could* have clarified a little better his
|thoughts, or at least given a range of directions.

Is there a way to do this without committing yourself?  Anything that
Bjarne puts in writing we, the C++ public, tend to hold him to it.

|Nevin Liber writes:
|# The folks at GNU seem to be resolving ambiguities by deciding what is
|# better for the *compiler*, and not what is (necessarily) better for the
|# *language*

|I agree on this, but with one obvious qualification: it often turns out that
|not only simplicity of implementation is an important pragamatic
|consideration, but it also is often true that design features that afford a
|simple implementation are also the most elegant for a language.

Yes, but often true != always true.  In those cases where these two
differ, I'd rather go along with Bjarne (better for the language) than
with GNU (better for the compiler).

|# (as evidence, I point to the recent discussion on why G++ uses an LALR(1)
|# grammar, instead of using the language defined by the C++ book).

|Good evidence. In part however this reinforces my previous paragraph:  their
|arguments that BS could have paid a little more attention to making parsing
|easy are in my opinion well founded; maybe I am assuming too much, but it has
|been my impression that the syntax "problems" are result of oversight; after
|all it is fairly hard to anticipate all possible consequences of rules in the
|design of a language.

|While I have not given much thought to the issue, I don't see much to lose in
|slightly changing syntax in the hard spots for the benefit of a parser, like
|a LALR parser.

As Bjarne stated in the C++ book (Implementation Notes, p3):

"..., where there was a choice between simplifying the manual and other
documentation or simplifying the compiler, the former was chosen.  Great
importance was also attached to retaining compatibility with C; this
precluded cleaning up C syntax."

By changing to a LALR grammar, g++ has violated the C compatibility
constraint!  While this may not be important for users of g++, those of
us who develop commercial software (where g++ can't easily be used, due to
licensing constraints) need C compatability so that we don't have to
rewrite millions of lines of old C code (this is also a good selling
point for management :-)).

Also, by requiring an LALR grammar, you will be less inclined to adopt
new features which cannot be expressed in the grammar, even though the
feature might be better for the language.

|# Designing a language is very different process than designing a compiler
|# for a language.  Defining the language based on how you want to write the
|# compiler tends to lead to trouble.

|A cautionary note: I agree that you want to DEFINE the language so that it is
|independent of any particular implementation, but the DESIGN had better take
|into account the possible implementations.

I'm sorry if I lead you to the impression that language design should
take place in a vacuum.  Of course language design must take into
account implementation!  When the language starts to become dependent on
the implementation, the trouble starts.


IMHO, the design of C++ has many parallels to designing a class within C++.
Think of the language definition as the class interface and the compiler as the
implementation of the class.  The class definition should not depend on the
class implementation; the metaphor should also hold for the language design.
-- 
NEVIN ":-)" LIBER  AT&T Bell Laboratories  nevin1@ihlpb.ATT.COM  (312) 979-4751

bader+@andrew.cmu.edu (Miles Bader) (12/31/88)

nevin1@ihlpb.ATT.COM (Liber) writes:
> IMHO, the design of C++ has many parallels to designing a class within C++.
> Think of the language definition as the class interface and the compiler as the
> implementation of the class.  The class definition should not depend on the
> class implementation; the metaphor should also hold for the language design.

In practice, you just can't get away with that all the time.
Sometimes nice interfaces prove to be horribly inefficient to
implement (Look at X [the window system]).  I always try and keep
possible implementations (just vague sketches) in mind when thinking
about the interface, so I don't end up having to redefining the
interface to make it implementable...

-Miles