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:
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 Randells group in Newcastle in the 1970s.
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 crucialas I still dothat 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 |