Design and evolution of the C ++ language: excerpts
In the comments to the translation of “30 years of C ++”, it was noticeable that not all stages of the evolution of a language are equally well known, sometimes there is no idea at all about the origin and development of a particular element of syntax or corresponding semantics. Perhaps this note will be able to interest readers turn to the not a new book by the author of the language for a long time in order to form a more complete picture of C ++. The book tells how its development took place, what influenced this process and why one approach was preferred over the other.
Below is a set of short excerpts from the book, presented in a free form and sometimes supplemented with examples. The order of presentation basically repeats the relative order of their appearance in the book. Numbering is used for possible references to individual items. There will be no intentional repetition of well-known facts here, since there is not much point in this. Attention was paid to just the lesser known of them and the most interesting from the point of view of the author of the post. Some items are quotations that say it all, some others just mention potentially interesting or funny facts. Also, many details are omitted, they should be sought in the book.
Some of the material intersects somewhat with recent posts, but has not been cut out for completeness. The order may seem chaotic, but then this is a sample, an additional reason for the "disorder" is indicated in the conclusion. When reading it is useful to bear in mind that the first edition of the book was published in early 1994. ')
Excerpts
It all started in 1971, when Bjorn Stroustrup needed a fast language to perform the simulation.
Dennis Ritchie was actively involved in discussing C ++ design. (You will see below how strongly C and C ++ influenced each other.)
“Initially, the language suggested general mechanisms for organizing programs, rather than supporting specific subject areas,” i.e. multi-paradigm in C ++ is inborn and corresponds to the idea of its author.
“I am sincerely convinced that there is no one correct way to write a program, and a language designer should not force a programmer to follow a certain style.”
The initial implementation did not support virtual functions.
Multiple inheritance was added years after the start of language development.
Initially, class constructors were called new and returned void (although it could be omitted). At the same time, the designers allocated memory for the object, and the destructors released it:
classstack {voidnew(); // new(); };
The original name of the destructors was delete and they also returned void (although it could be omitted):
classstack {voiddelete(); // delete(); };
Instead of a double colon ( :: :), a dot was used to declare the class methods:
charstack.pop() { // ... }
Class names were in a separate namespace and had to be preceded by the class keyword (as well as struct / union in C):
classstackstack;classstack *thatStack = &stack;
The very keyword class came from Simula, and since Björn is not a fan of inventing terminology, he left what he was used to.
Simula language allowed to create instances of classes only on the heap, which was extremely inconvenient and gave the idea to allow them to be created in C ++ on the stack or globally.
“C ++ is just another language in the system, not the whole system.”
In the first implementation, it was not possible to access this , but this was largely due to an error.
Autoprototyping (output and memorization of a prototype of an unknown function in the place of its first access) was originally invented for C ++, but was later used in C (although it is now deprecated):
function(1, 1.0); // , function int double. function("string"); // - int double.
The declaration of a function that does not accept arguments using (void) was added first in C ++, and only then in C (then in C ++ this idea was already abandoned and decided to use empty parentheses):
voidnoArgsInCpp(); voidnoArgsInCAndCpp(void);
Declaring an implicit int as stale was originally proposed for C ++:
function() {} // , function int.
In the early periods, attempts were made to prohibit narrowing transformations ( long -> int , double -> int ), but because of too high prevalence, it was decided to abandon this idea:
voidf(long lng, int i){ i = lng; // . char c = i; // . }
Operator overloading, references and the ability to declare variables anywhere in the block came from ALGOl 68 .
Sources used in the development of exceptions: Ada , Clu , ML .
Patterns and namespaces are borrowed from the Ada language.
Specifying the types of parameters in the function declaration is first implemented in C ++, later adapted to C.
The possibility of introducing an alternative syntax of declarations was considered (recently there was a post on a related topic):
// : v: [10]->int; // int *v[10]; p: ->[10]int; // int (*p)[10]; // : int v[10]->; // int *v[10]; int p->[10]; // int (*p)[10]; int f(char)->[10]->(double)->; // int *(*(*f(char))[10])(double);
The new syntax was not worked out in all its details and it never got into the language due to the small significance of the change against the background of potentially large backward-compatibility problems.
The refusal of mandatory type prefixes ( struct / union / class ) led to the possibility of declaring variables that coincide by name with classes (for the most part, for compatibility with C):
classClass { }; intmain(){ Class Class; return0; }
At one time, it was allowed to declare new composite types in the argument list, or directly in the return value of the function:
classA {// ... } get() { return A(); }
Previously, “pulling out” the members of the base classes did not require the use of the using keyword, it was enough just to specify the name of the member:
classBase {protected: voiddoSomething(); voiddoSomethingElse(); }; classDerived :public Base { public: doSomething; // using doSomething; Base.doSomethingElse; // using doSomethingElse; };
Initially, only classes could be friendly. The general idea of the concept is to place a number of entities in a single security domain, the members of which are equal in rights (and not encapsulation violation, as it may seem that, however, does not cancel the possibility of such use).
Perhaps it was Stroustrup who invented the concept of the designer.
Initially, each object could contain the call() and return() methods, which were called, respectively, before and after the execution of any method of the class. Similar methods :before and :after are in CLOS .
Later decided that this feature adds more difficulty in the language than brings benefits.
The possibility of including the garbage collector in the language was considered several times, but was considered unacceptable.
Direct support for multithreading was also considered, but it was decided to leave it for implementation as a library.
For a while, the language was called C84 to avoid confusion, since users replaced C with classes with something like “new C”, “improved C”, etc. Optimistically considering that C will be standardized in 1985, Björn was asked to change the name again, in order to avoid possible ambiguity with the “standard C”.
The first C ++ compiler (not the preprocessors that were used initially) was written in C ++ (Cfront, C with classes and C84, it seems, were written in C).
Cfront was probably the first incomplete loop compiler generating code in C. It was followed by Ada, Eiffel , Lisp , Modula-3 , Smalltalk .
The first implementation of exceptions was added by Hewlett-Packart in 1992.
Virtual functions were borrowed from Simula, but with modifications.
Type definition at runtime was not originally added intentionally to force users to use static type control and virtual functions, rather than a run-time type, which is essentially a switch .
struct almost equivalent to class for the purpose of uniformity and unification.
Before Cfront 2.0, operator= could be a global function; later, this idea was abandoned due to conflicting predefined semantics.
classC {}; C & operator=(C &rhs) {} // : // src.cpp:3:21: error: 'C& operator=(C&)' must be a nonstatic member function
The definition of a variable at its place of use is taken from ALGOL 68.
Links are also borrowed from ALGOL 68, but there they could be reassigned after initialization.
Overload on lvalue / rvalue was considered at the time of Cfront 1.0.
readonly / writeonly pointers / data were invented by Straustrup and Dennis Ritchie in 1981, and were later added to the standard C by the ANSI C (X3J11) committee, but in a somewhat truncated form: only readonly and after renaming it to const .
The new keyword is also taken from Simula.
The initial implementation of object allocation assumed the assignment of this in the constructor.
constructor / destructor as the names of the corresponding special methods were rejected to reduce the number of keywords, as well as for more obvious syntax.
The new() and delete() functions (the old constructor and destructor names) in C with classes, by default, automatically received the public access public .
Operator :: was introduced to resolve ambiguity with a dot.
Initially, the variables entered in the for initialization list were visible after its body (due to inaccurate wording “names are visible from the declaration point to the end of the area”). Many have probably come across this in Borland C ++.
for (int i = 0; i < n; ++i) { // ... } if (i >= n) { // i, for.
Nested class scopes were added, later removed for compatibility with C and re-added again.
Maybe someone else will be news, but Pascal also has ISO / IEC standards (there are just not enough of these languages).
The proposal to add named arguments was considered, but rejected. (While reading the book, the impression was that a rather large number of different proposals were rejected; however, a lot of this still fell into the standard after decades.)
restrict (noalias) pointers were never adapted from C even though they were known in the early 90s.
Special characters caused C distribution problems in Europe due to the wide use of 7-bit encodings. From here came the trigraphs, digraphs and special words ( and , or , etc .; see. ). All this migrated to C ++.
The budget that AT & T has allocated in C ++ for all time is approximately $ 3000. Of these, $ 1000 went to the C ++ advertising newsletter to UNIX buyers and $ 2000 to the first conference, at which everything was more than modest (even the paper was not enough, the volunteers made copies of technical documentation on the visitors registration forms ...). Nevertheless, the absence of any marketing for decades did not prevent the widespread use of the language.
Conclusion
In conclusion, I would like to mention the somewhat nonstandard structure of the book (so the order of the points might seem strange) with an increase in the level of detail in each of the parts, as well as the fact that it describes well the principles that Straustrup tries to adhere to and justify them. Therefore, it should be interesting not only to C ++ programmers, but also to many who are interested in programming languages in general.