Summary
Bjarne Stroustrup talks with Bill Venners about many aspects of software design,
including growing small applications into larger ones, avoiding class distinctions
between designers and users, the dangers of premature generalization, and the
essence of elegance.

Bjarne Stroustrup is the designer and original implementer of C++. He is the
author of numerous papers and several books, including The C++ Programming
Language (Addison-Wesley, 1985-2000) and The Design and Evolution of
C++ (Addison-Wesley, 1994). He took an active role in the creation of the
ANSI/ISO standard for C++ and continues to work on the maintenance and revision
of that standard. He is currently the College of Engineering Chair in Computer
Science Professor at Texas A&M University.

On September 22, 2003, Bill Venners met with Bjarne Stroustrup at the JAOO
conference in Aarhus, Denmark. In this interview, which is being published in
multiple installments on Artima.com, Stroustrup gives insights into C++ best
practice.

In Part II: Modern C++ Style, Stroustrup discusses using multiple
inheritance and pure abstract classes, multi-paradigm programming, and the
technique of resource acquisition is initialization.

In Part III: Abstraction and Efficiency, Stroustrup discusses
raising the level of abstraction, why programming is understanding, how "oops happens," and the difference between
premature and prudent optimization.

In this fourth and final installment, Stroustrup discusses many aspects of software design,
including growing small applications into larger ones, avoiding class distinctions
between designers and users, the dangers of premature generalization, and the
essence of elegance.

Thinking Before You Code

Bill Venners: In an interview with Biltek, you said, "I'm not a great believer in
elaborate design methods with supporting tools. I am, however, a strong supporter of
systematic use of data abstraction, OOP, and generic programming. Anyone who just sits
down and writes page after page of code without an overall design and without
supporting classes and templates is simply wasting time and creating unnecessary
maintenance problems." How much up-front design would you recommend. How much
should we think before we code?

Bjarne Stroustrup: That depends so much on the size of the problem. If you have
to write a little program that you need this afternoon, the design would probably would fit
on the back of an envelope. If you are building a system that has to live for years and
takes years to build, then clearly, you have to do more up-front design. If many people are
involved in the project, you have to do more up-front design. However, the larger the
system, the harder the up-front design becomes. Design tools don't give you much
feedback, so therefore I tend towards the view that you should build a smaller system and
grow it into a bigger one. There is a rule of thumb that says that every successful large
system is a development of a slightly smaller working system. You apply that
rule recursively.

Some people might think I'm talking about building prototypes. I am to some extent, but that's not all
I'm talking about, because prototypes can also be a trap. If you build a prototype using a
different class of developer, a different class of tools, and a totally different workload than the real application,
you can get into really difficult problems. For example, you can afford much more hardware per user, much more
software overhead, and much more experienced developers in the development of a prototype supporting ten users
than if you have to support ten thousand users. You can usually also afford to ignore inconvenient standards
issues and compatibility problems in a prototype. And then, of course, some solutions just don't scale.

Sometimes you can build part of the functionality of a system to try it out. I'm rather keen
on doing very early integration tests. You decide what tools you want to use, and you
write the logical equivalent of "Hello, world!" For instance, in a distributed system, you
start off with the tiniest example you can of the application on the different parts of the
system, and let them try and talk to each other. That's when you find that your Java ORB
won't talk to your C++ ORB, or your Java virtual machine on the HP will not talk to the
Java virtual machine on the Sun, or whatever. Obviously, such things that should never happen,
but they do; maybe not the particular problems I mentioned here, but something unexpected always happens.
I'm not just talking about prototypes. I'm talking about experiments and trying out all the things that
eventually would have to work. Try them out early.

Thinking in Libraries

Bill Venners: I've often heard you state that C++ supports library design. To
what extent to you think programmers who are just building applications should think of
themselves as library designers? Should we partition our application into this library and
that library? Or should we only think in terms of library design when we're creating a
library for others to use?

Bjarne Stroustrup: I think people should mentally separate programming into
building libraries and using them. Today you write a supporting library, and tomorrow
you use it. Far too many times people try and build their systems as one big
conglomerate. Even when I do individual work for only a short time, I tend to build some
supporting functions and classes, and I design them to be supporting. I don't dive straight
into building the whole thing that can do the whole job. So, whether you are by title a library
designer or application designer, you should think about how you can separate
logically the different parts of your system.

One of the problems with C++ is that there are too many libraries, and not any common
marketplace or meeting place where people can find libraries and information about libraries.
The problem with C++ and GUI is not that there's no C++ GUI library, for instance. The problem
is that there are about 25 reasonable C++ GUI libraries, of which a few are rather good. But
people say, "Well, there's no C++ GUI.
It's not in the standard." C++ has no common meeting place like there is for Python, for example,
where you know you can find libraries. It's a problem of riches, plurality, and a lack of marketing.
Nobody in the C++ world seems to have any money to provide such a common meeting place.

One way you shouldn't write libraries is by taking the view that you are the great library
designer. You provide the library for me. I use it, and you go away and do something else.
You have to think of a library as something you yourself are using, and something that you have
to live with as a support person for a longish while. You have to talk a lot to users to get the
right abstractions and the right practical details. A library has to evolve.
The best libraries are by people who are also users
of the libraries. You can't have a class distinction between designers and users.

What to Leave In, What to Leave Out

Bill Venners: C++ has a lot of stuff in it. The more features that a
designer puts into a language or library, the more power the users get, but also the more
surface area they get. There are more features users have to know about, even if it is
knowing they just want to ignore certain features. As a designer of a language or
library, how do you decide what features to leave in what to leave out?

Bjarne Stroustrup: It's very hard. I don't have a good enough philosophical base
for that, and neither has just about anybody else. In the C++ language, I try to put in what will help
everybody as opposed to what will help a particular group. I try to put in very general
facilities. For example, I don't put in specific features for GUIs, because lots of people
don't put GUIs in in their programs. I don't put in specific features for databases, because
lots of people don't use databases. I don't put in specific features for concurrency, because
you can put them in a library. So I go for generality, for features that in principle will be
used by everybody, directly or indirectly. And I try not to force people to do lots of
repetitive, tedious stuff. My work with templates, inlines, and overloading to eliminate
dangerous casts and repetition is probably the best example.

Of course, you can say that everything I just said could be applied either to the design of a
language itself or to the design of a standard library that everybody's using, or should be
using. And it is very
hard to define exactly where you should draw the line between a language and its
libraries. In C++, I have tended to build into in the language facilities that are abstraction
mechanisms. So contrary to some languages, I have not put in an advanced vector,
because I could do that in a library with the facilities provided by the language. I didn't provide a string with
special facilities for string manipulation. Instead, I put in general mechanisms that allow you to
write a string class. I didn't put in properties because you can write a properties class.
So in that sense, I go against some of the currently fashionable trends in other languages to
put in very specific and specialized facilities. I guess that's a kind
of basic philosophy of mine.

If you want more detail, read The Design
and Evolution of C++, which is where I document a lot about why C++ is designed
the way it is. Among other things, reading that book will help you avoid things
like people—in this case, me—being wise after the event and trying to
change history retrospectively. That book is a fairly solid record of what I
thought at the time. There is unfortunately a lot of revisionist history in the
computing world. Interestingly enough, the C++ language hasn't changed since I
described in The Design and Evolution of C++. What has changed is the
standard library and some of the styles of usage.

Protecting People From Themselves

Bill Venners: Language and library designers often think about protecting users
from themselves, but in C++, you seem to operate more from the philosophy that
designers should give people enough rope to shoot themselves in the foot. In your C++
FAQ, you write, "As you protect people from simple dangers, they get themselves into
new and less obvious problems." In our designs, how much should we try to shield
users from their own potential mistakes?

Bjarne Stroustrup: I'm not as paternalistic as some language designers. I may
have romantic notions of how competent users—in this case programmers—are, but I
don't consider programmers on average stupid, and I would like to see them as more
respected professionals. I wish programmers would act professional more often and that
people would be willing to pay for more competence.

In addition, I don't want to
disenfranchise users by giving them facilities that allow them to only do so much.
I often see systems that require their users, if they want to do more than the system directly
provides, to go back to the system vendor and ask the vendor to provide new facilities.
The best examples are some of the fourth generation languages and tools for generating code
from models or diagrams. If some facility you require
was not thought of by the designer and is not built into the tool, you basically have to go
back to the tool vendor and ask for a change in the tool. I have seen an example where a
customer couldn't easily define a new sort operation. A related example is languages where
you can't write the standard libraries, let alone the advanced libraries, in the language itself.
That means you separate the user population into the untrusted developer group and the
trusted and privileged group that tends to work for the supplier.

I prefer to see everybody
on a reasonably even keel. My ideal is that if you don't like the libraries your vendor ships,
you can build your own, because you have the same tools available. That idea doesn't seem to be
fashionable among tools and platform vendors either.

C was designed with the principle that you should be able to write its standard library in
the language itself. That same principle guided the design of C++. I don't think it's a
principle in just about any other language. What other languages do is write their
implementation in C or C++ instead. That approach works, but it runs the risk of having
the great unwashed masses writing in some more protective language, and the specialists,
working for the vendor, writing in the language where the actual work can be done.
Once you have generality, you can get safety though coding standards or libraries;
preferably through domain-specific coding standards supported by libraries.

Design Beyond Imagination

Bill Venners: In an interview with Rogue Wave, you said, "I wouldn't like to
build a tool that could only do what I had been able to imagine for it."

Bjarne Stroustrup: Yes.

Bill Venners: How do we do that? How do we design for situations we can't
imagine?

Bjarne Stroustrup: You listen to a lot of people and then you aim for generality.

Bill Venners: By generality do you mean more abstract
solutions to specific problems? Or do you perhaps mean facilities that a lot of people will
need to use? Define generality.

Bjarne Stroustrup: Let's take an example. A class can do just about anything.
C++ does not have separate language constructs to specify classes for big objects, for
small objects, for object-oriented classes, for value types, for GUI events, for properties,
for threads, and so on. The C++ class concept is general enough to allow a user to specify
all of those, and to do so efficiently.
One example of generality in the design of C++, then, is that I didn't decide that classes should be only for
big expensive operations because it's expensive to call them.

In addition to generality in the sense that you're not
restricting users, you can also aim for generality in the mathematical sense.
You make make sure all the cases work, that a whole logical design space is covered, as opposed to saying
there are these five features you should be able to do and no more.
Why five? When you design in terms of lists of features or lists of alternatives, you never get the design quite right.
There always turns out to be just one more case, or one less.
For example, in C++ there are no built-in facilities for doing exactly the
events system for a particular operating system. There are general mechanisms with
which you can write a class that does an events system for any operating system.

Premature Generalization

Bill Venners: Going back to the topic of the application designer who is thinking in terms of
libraries, when should they put in general facilities versus
specifically solving the problem that they have before them?

Bjarne Stroustrup: I really don't know. That's such a general question, and an
honest answer must include "sometimes" and "it depends."
I think I have a tendency to build the specific case first if I haven't tried something several
times before, because it is pretty fundamental that we understand the concrete solution better
than the abstract.
When I see the same problem
again and I get half way into the solution, I say, "Wait a minute, I'm doing the same thing
twice." I did it once. I sort of understand it. I know what I mistakes I made in the
previous solution. Now is the time to step back and see if I can have a general solution.
That approach contrasts with the approach taken by people who start generalizing before
they've tried it once—they sit trying to design a general solution to a problem that they
have no experience with.

Bill Venners: That sounds like premature generalization.

Bjarne Stroustrup: Yes, that's right. You can have premature generalization as
well as premature optimization.

Ugly Syntax for Ugly Operations

Bill Venners: In your C++ Style and Technique FAQ, you say, "An
ugly operation should have an ugly syntactic form." I thought that was an interesting
approach to design. You want to discourage users from doing something, but you don't
want it to be impossible for them to do it when they really need to, so you provide a way, but
make it ugly.

Bjarne Stroustrup: Yes. That's the new cast syntax. Casts do provide an essential service.
The new syntax is an improvement over the C-style casts because it allows the compiler to check
for errors that it couldn't with the old syntax. But the new syntax was made deliberately ugly,
because casting is still an ugly and often unsafe operation.

Elegance and Other Design Ideals

Bill Venners: What should our ideals and aims be when we are designing, and
why? You talk about "elegance" a lot. What is the business return on investment for
elegance, or whatever it is you think should be our goal in design?

Bjarne Stroustrup: "Elegant" and "simple" are very related words. "Understandable" is
another word in that area. What do they mean? It comes to down to: you can apply tools
to your program. You can optimize it. You can maintain it. You can port it. If you can
logically identify something, you can deal with it. If it's just a bunch of code scattered
throughout a large program, you can't do a thing with it.

One of the most elegant things, by
the way, is something that's declarative. It's one of the reasons I like statically typed
languages. You can say: this is a matrix of double precision floating point numbers. Now
you know a lot. You know what it means to multiply. You have a whole theory for matrices.
When you declare a class with a constructor and destructor and then make an object,
it has been declaratively said that the resource will be released in the destructor. It's clear.
It's right there. Humans gain understanding. Both humans and tools can do things.

When I use elegant,...

Bill Venners: Yes, what does elegant mean?

Bjarne Stroustrup: It's hard. If you see a proof in math, you can say it's elegant.
It's as clear, as general, as short as you can make it. I was trained as a mathematician, among
other things, and I think that's the kind of notion that shines through. There's an aesthetic
here, but the aesthetic correlates very strongly to things people really want, like
maintainability and reasonably fast development, because you're working at a higher level
of abstraction and using higher level constructs. And there's efficiency if you want it.

I keep telling my students that they should be lazy. I reject programs that are too long,
because when students get to do real work, they won't have time to write that much code. A
lot of the things I call elegant you'll find are short compared to alternatives.
One of the things that amazes people is when you compare good C++ code to good code in other
languages, the C++ code tends to be shorter. C++ code is shorter when it's written in terms of
things like the standard library or other good libraries, because you can express ideas very
succinctly.
That's one of my ideals.
Say what you want. Say it clearly. Say it as generally as possible.
You'll find the resulting code is relatively short and it will probably run fast too.

Next Week

Come back Monday, March 1 for the next installment of a conversation with
Bertrand Meyer.
If you'd like to receive a brief weekly email
announcing new articles at Artima.com, please subscribe to
the Artima Newsletter.

Enough Rope to Shoot Yourself in the Foot, a phrase Bill Venners mentioned in this interview in the context of the
question about protecting users from themselves, is the title of
a book of C/C++ style guidelines by Alan Holub:http://www.amazon.com/exec/obidos/ASIN/0070296898/