Santa Barbara (California)
Ph: 805-685-1006, fax 805-685-6869,
Some have described Eiffels design as inhibitive or constraining. As was once put by a C++ programmer in a `Eiffel vs C++' exchange:For me, Eiffel was kind of like a chastity belt. It definitely keeps you "pure" but you will probably have less fun. It struck me, in fact, that a good many of [B. Meyer]'s comparisons between C++ and Eiffel boiled down to "C++ lets the programmer foul things up in any way he pleases, while Eiffel insists on doing it right". This is, in fact, a long-standing philosophical difference between the C camp and the Pascal camp.The debate, which is older and broader than the question of C versus Pascal, is indeed an important one: How restrictive and prescriptive may a language designer be in forcing a particular approach to software construction upon the users of the language?
However their application to the design of Eiffel may be judged, I can at least clarify my intentions.
- ``Chastity belts'' are inappropriate. A chastity belt prevents its holder from doing things that are desirable and enjoyable. A language designer is not a guardian of moral order.
- A good programming language is one that helps programmers write good programs. No programming language will prevent its users from writing bad programs.
[If I recall correctly, this is an observation I first heard a long time ago from Kees Koster, who among other things is the designer of the CDL language.]
- Some constructs are known to be dangerous, meaning that programs employing them are prone to contain damaging errors. In any language meant for industrial production, it is the language designer's responsibility to exclude such constructs.
Examples include type casts, user-controlled memory deallocation, pointer arithmetic, programmer-specified routine inlining, etc.
- The purpose of excluding a construct is not to prevent programmers from writing bad programs or doing ``dangerous things'' if they want to. (See points 1 and 2.) Instead, a construct is excluded because it is known to lead programmers to make mistakes even when applied towards legitimate goals.
This highlights the basis for all this discussion. In the same way that the author of a novel has a typical reader in mind, the designer of a programming language is, consciously or not, designing for a typical programmer. We should assume (as was done for Eiffel) that this typical programmer is intelligent and reasonable. The restrictive parts of the language design are not meant to prevent the programmer from being ``bad'', but rather to help him avoid known pitfalls and involuntary mistakes.
- For the language designer, excluding a construct is not a solution but a problem.
In all likelihood the excluded construct addressed some legitimate need, albeit in an inadequate way. The designer must find a better technique to satisfy the same need. This is the difficult part, of course: exclusion is easy. Sometimes the solution is a better programming language construct; in other cases the problem is best handled by the implementation (compiler and programming environment).
For example, unrestrained type casts may be replaced by inheritance-controlled polymorphism; garbage collection should be under the control of the run-time system; pointer arithmetic is unneeded in the presence of type-safe dynamic binding; and in-line routine expansion should be the responsibility of an optimizing compiler.
- Literal compatibility with previous languages should not be a criterion. People will learn a new language quickly if its design is simple and consistent. One should learn from the mistakes of the past, not perpetuate them.
Some care should be exercised, however, when one deals with programmers' current habits. For example, a new language should not use an existing notation in a way that confusingly departs from its accepted semantics. (The Eiffel assignment operator, :=, is a case in point; its semantics would probably have been different were it not for the fear of confusing Algol-Pascal-Ada programmers.)
- Perhaps my major personal guideline is to maximize the signal-to-noise ratio of the language.
Exclude constructs that just add complexity to the language without bringing any significant new possibility (for example, varieties of loops); include constructs that tersely and elegantly address a large number of practical situations.
- Any occurrence in a language description of a sentence of the form ``Be careful when using this construct'' implying that its use may have dangerous consequences, is an avowal of failure on the designer's part. Programmers should be encouraged to use the entire language, not a subset.
The programming language is the software developers' fundamental tool. They should know, love and trust all of it.
- Hard as you try to maximize the signal-to-noise ratio, there may remain cases in which special needs require special facilities.
Such special facilities should be limited to only one situation: the need to access low-level internal or machine-dependent elements. In my opinion, this is best addressed by techniques that fall outside of the language proper, such as machine-code insertions in Ada or external routines in Eiffel.
To avoid violating the previous criterion (8), there should be very few such techniques, and they should never be needed in normal uses of the language. In Eiffel their typical uses have been encapsulated in the library (essentially in the class called INTERNAL) and their application is limited to the following cases:
In summary, the aim of what above was called a more ``pure'' design is not to prevent programmers from ``fouling things up'' but to enable them to do things in a way that is at the same time safer, more elegant, more powerful and more convenient. Reconciling these goals is the main challenge in designing a better programming language.
- Interfacing with elements on which the language design has no control: existing software tools (for example, relational data base management systems) or software written in other languages.
- Machine-dependent programming.
- Implementation of facilities which are part of the basic environment (such as the ARRAY and STRING classes in the kernel Eiffel library).
- Facilities which the language designer feels are not necessary, while recognizing that some language users may disagree on this point. There is one example of this in Eiffel: class INTERNAL contains a procedure free which will explicitly return an object to the free store. In our opinion it should never be used, and none of our own software ever uses it; however we accept that some users may disagree and would rather provide the corresponding facility in an ``official'' form than encourage these users to fool around with internal formats.
Coming back to the first two lines of the above extract:For me, Eiffel was kind of like a chastity belt. It definitely keeps you "pure" but you will probably have less fun.Eiffel programmers can have fun, too, thank you. Of course, someone whose idea of fun is to spend his or her nights debugging will have less of it. But then such a person wouldn't need a chastity belt anyway.