Previous Table of Contents Next


6.2. C with Classes: 1979-1983

C++ evolved from an earlier version of C called C with Classes. The work and experience with C with Classes from 1979 to 1983 determined the shape of C++.

6.2.1. Prehistory of C++

The prehistory of C++—the couple of years before the idea of adding Simula-like features to C occurred to me—is important because during this time the criteria and ideals that later shaped C++ emerged. I was working on my Ph.D. thesis in the Computing Laboratory of Cambridge University in England. My aim was to study alternatives for the organization of system software for a distributed system. The conceptual framework was provided by the capability-based Cambridge CAP computer and its experimental and continuously evolving operating system (Wilkes & Needham, 1979). The details of this work and its outcome (Stroustrup, 1979a) are of little relevance to C++. What is relevant, however, was the focus on composing software out of well-delimited modules and that the main experimental tool was a relatively large and detailed simulator I wrote for simulating software running on a distributed system.

The initial version of this simulator was written in Simula and ran on the Cambridge University computer center’s IBM 360/165 mainframe. It was a pleasure to write that simulator. The features of Simula were almost ideal for the purpose, and I was particularly impressed by the way the concepts of the language helped me think about the problems in my application. The class concept allowed me to map my application concepts into the language constructs in a direct way that made my code more readable than I had seen in any other language. The way Simula classes can act as co-routines made the inherent concurrency of my application easy to express. For example, an object of class computer could trivially be made to work in pseudo-parallel with other objects of class computer. Class hierarchies were used to express variants of application-level concepts. For example, different types of computers could be expressed as classes derived from class computer, and different types of inter-module communication mechanisms could be expressed as classes derived from class IPC. The use of class hierarchies was not heavy, however; the use of classes to express concurrency was much more important in the organization of my simulator.

During writing and initial debugging, I acquired a great respect for the expressiveness of Simula’s type system and its compiler’s ability to catch type errors. The observation was that a type error almost invariably reflected either a silly programming error or a conceptual flaw in the design. The latter was by far the most significant and a help that I had not experienced in the use of more primitive “strong” type systems. In contrast, I had found Pascal’s type system worse than useless—a straitjacket that caused more problems than it solved by forcing me to warp my designs to suit an implementation-oriented artifact. The perceived contrast between the rigidity of Pascal and the flexibility of Simula was essential for the development of C++. Simula’s class concept was seen as the key difference, and ever since, I have seen classes as the proper primary focus of program design.

I had used Simula before (during my studies at the University of Aarhus in Denmark) but was very pleasantly surprised by the way the mechanisms of the Simula language became increasingly helpful as the size of the program increased. The class and co-routine mechanisms of Simula and the comprehensive type-checking mechanisms ensured that problems and errors did not (as I—and I guess most people—would have expected) grow linearly or more than linearly with the size of the program. Instead, the total program acted more like a collection of small (and therefore easy to write, comprehend, and debug) programs rather than a single large program.

The implementation of Simula, however, did not scale in the same way, and as a result, the whole project came close to disaster. My conclusion at the time was that the Simula implementation (as opposed to the Simula language) was geared to relatively small programs and was inherently unsuited for larger programs (Stroustrup, 1979a). Link times for separately compiled classes were abysmal: It took longer to compile 1/30 of the program and link it to a precompiled version of the rest than it took to compile and link the program as a monolith. This I believe to be more a problem with the mainframe linker than with Simula, but it was still a burden. On top of that, the runtime performance was such that there was no hope of using the simulator to obtain real data. The poor runtime characteristics were a function of the language and its implementation rather than a function of the application. The overhead problems were fundamental to Simula and could not be remedied. The cost arose from several language features and their interactions: runtime type checking, guaranteed initialization of variables, concurrency support, and garbage collection of both user-allocated objects and procedure activation records. For example, measurements showed that more than 80% of the time was spent in the garbage collector despite the fact that resource management was part of the simulated system so that no garbage was ever produced. Simula implementations improved, but the order-of-magnitude improvement relative to systems programming languages did not (to the best of my knowledge) materialize.

To avoid terminating the project, I rewrote the simulator in BCPL and ran it on the experimental CAP computer. The experience of coding and debugging the simulator in BCPL was horrible. BCPL makes C look like a very high-level language and provides absolutely no type checking or runtime support. The resulting simulator did, however, run suitably fast and gave a whole range of useful results that clarified many issues for me and provided the basis for several papers on operating system issues (Stroustrup, 1978, 1979b, 1981b).


Previous Table of Contents Next