Previous Table of Contents Next


Upon leaving Cambridge, I swore never again to attack a problem with tools as unsuitable as those I had suffered while designing and implementing the simulator. The significance of this to C++ was the notion I had evolved of what constituted a “suitable tool” for projects such as the writing of a significant simulator, an operating system, and similar systems programming tasks:

  A good tool would have Simula’s support for program organization—that is, classes, some form of class hierarchies, some form of support for concurrency, and strong (that is, static) checking of a type system based on classes. This I saw as support for the process of inventing programs, as support for design rather than just support for implementation.
  A good tool would produce programs that ran as fast as BCPL programs and share BCPL’s ability to easily combine separately compiled units into a program. A simple linkage convention is essential for combining units written in languages such as C, Algol68, Fortran, BCPL, and assembler into a single program and thus not get caught by inherent limitations in a single language.
  A good tool should also allow for highly portable implementations. My experience was that the “good” implementation I needed would typically not be available until “next year” and only on a machine I couldn’t afford. This implied that a tool must have multiple sources of implementations (no monopoly would be sufficiently responsive to users of “unusual” machines and to poor graduate students), that there should be no complicated runtime support system to port, and that there should be only very limited integration between the tool and its host operating system.

Not all of these criteria were fully formed when I left Cambridge, but several were and more matured on further reflection on my experience with the simulator, on programs written over the next couple of years, and on the experiences of others as learned through discussions and reading code. C++ as defined at the time of Release 2.0 strictly fulfills these criteria. The fundamental tensions in the effort to design templates and exception-handling mechanisms for C++ arise from the need to depart from some aspects of these criteria. I think the most important aspect of these criteria is that they are only loosely connected with specific programming language features. They do not specify solutions to specific problems. Rather, they specify constraints on solutions. Over the years, the initial criteria developed into a more comprehensive set that guided the design and evolution of C++ (Stroustrup, 1994).

My background in operating systems work and my interest in modularization and communication had permanent effects on C++. The C++ model of protection, for example, is based on the notion of granting and transferring access rights, the distinction between initialization and assignment has its root in thoughts about transferring capabilities, and the design of C++’s exception-handling mechanism was influenced by work on fault-tolerant systems done by Brian Randell’s group in Newcastle in the 1970s.

6.2.2. The Birth of C with Classes

The work on what eventually became C++ started with an attempt to analyze the UNIX kernel to determine to what extent it could be distributed over a network of computers connected by a local area network. This work started in April 1979 in the Computing Science Research Center of Bell Laboratories in Murray Hill, New Jersey. Two sub-problems soon emerged: how to analyze the network traffic that would result from the kernel distribution and how to modularize the kernel. Both required a way to express the module structure of a complex system and the communication pattern of the modules. This was exactly the kind of problem that I had become determined never to attack again without proper tools. Consequently, I set about developing a proper tool according to the criteria I had formed in Cambridge.

In October 1979, I had a preprocessor called Cpre that added Simula-like classes to C running, and in March 1980, this preprocessor had been refined to the point where it supported one real project and several experiments. My records show the preprocessor in use on 16 systems by then. The first key C++ library, the task system supporting a co-routine style of programming (Shopiro, 1987; Stroustrup, 1980b, 1987b), was crucial to the usefulness of C with Classes (as the language accepted by the preprocessor was called) in these projects.

During the April to October period, the transition from thinking about a tool to thinking about a language had occurred, but C with Classes was still thought of primarily as an extension to C for expressing modularity and concurrency. A crucial decision had been made, however. Even though support of concurrency and Simula-style simulations was a primary aim of C with Classes, the language contained no primitives for expressing concurrency; rather, a combination of inheritance (class hierarchies) and the ability to define class member functions with special meanings recognized by the preprocessor was used to write the library that supported the desired styles of concurrency. Please note that “styles” is plural. I considered it crucial—as I still do—that more than one notion of concurrency should be expressible in the language. This decision has been reconfirmed repeatedly by me and my colleagues, by other C++ users, and by the C++ standards committee. There are many applications for which support for concurrency is essential, but there is no one dominant model for concurrency support; thus, when support is needed, it should be provided through a library or a special-purpose extension so that a particular form of concurrency support does not preclude other forms.

Thus, the language provided general mechanisms for organizing programs rather than support for specific application areas. This was what made C with Classes and later C++ a general-purpose language rather than a C variant with extensions to support specialized applications. Later, the choice between providing support for specialized applications or general abstraction mechanisms came up repeatedly. Each time, the decision was to improve the abstraction mechanisms.


Previous Table of Contents Next