Abstract What? 211 class. In most cases, changing a class forces a recompile of all code that could possibly reference it. This typically brings work to a standstill while entire systems must be recompiled. Your software is no longer “soft” and malleable it’s more like quick-setting cement. Of course, you have to put half of your code in the header files, just to declare your classes to the rest of the world. Well, of course, the public/pri- vate distinctions provided by a class declaration are worthless since the “private” information is in the headers and is therefore public information. Once there, you’re loathe to change them, thereby forcing a dreaded recompile. Programmers start to go to extraordinary lengths to add or change functionality through twisted mechanisms that avoid changing the headers. They may run into some of the other protection mechanisms, but since there are so many ways to bypass them, these are mere speedbumps to someone in a hurry to violate protocol. Cast everything as void* and presto, no more annoying type checking. Many other languages offer thoughtfully engineered mechanisms for dif- ferent kinds of abstraction. C++ offers some of these, but misses many important kinds. The kinds it does offer are confused and hard to under- stand. Have you ever met anyone who actually likes using templates? The result is that the way many kinds of concepts are expressed depends on the context in which they appear and how they are used. Many important con- cepts cannot be expressed in a simple way at all nor, once expressed, can they be given a name that allows them subsequently to be invoked directly. For example, a namespace is a common way of preventing one set of names appropriate to one part of your code from colliding with another set of names from another part. A program for a clothing manufacturer may have a class called Button, and it may be linked with a user interface tool- kit with another class called Button. With namespaces, this is no problem, since the rules for the usage and meaning of both concepts are clear and easy to keep straight. Not so in C++. There’s no way to be sure you haven’t taken a name used somewhere else in your program, with possibly catastrophic consequences. Your only hope is to garble up your code with nonsensical prefixes like ZjxButton and hope nobody else does the same. Date: Fri, 18 Mar 94 10:52:58 PST From: Scott L. Burson gyro@zeta-soft.com Subject: preprocessor
212 C++ C weenies will tell you that one of the best features of C is the pre- processor. Actually, it is probably the worst. Many C programs are unintelligible rats’ nests of #ifdefs. (Almost none of which would be there if the various versions of Unix were actually compatible.) But that’s only the beginning. The worst problem with the C preprocessor is that it locks the Unix world into the text-file prison and throws away the key. It is virtually impossible to usefully store C source code in any form other than lin- ear text files. Why? Because it is all but impossible to parse unpre- processed C code. Consider, for instance: #ifdef BSD int foo() { #else void foo() { #endif /* ... */ } Here the function foo has two different beginnings, depending on whethe the macro ‘BSD’ has been defined or not. To parse stuff like this in its original form is all but impossible (to our knowledge, it’s never been done). Why is this so awful? Because it limits the amount of intelligence we can put into our programming environments. Most Unix pro- grammers aren’t used to having such environments and don’t know what they’re missing, but there are all kinds of extremely useful fea- tures that can easily be provided when automated analysis of source code is possible. Let’s look at an example. For most of the time that C has been around, the preprocessor has been the only way to get expressions open-coded (compiled by being inserted directly into the instruction stream, rather than as a function call). For very simple and com- monly used expressions, open-coding is an important efficiency tech- nique. For instance, min, which we were just talking about above, is commonly defined as a preprocessor macro: #define min(x,y) ((x) (y) ? (x) : (y)) Suppose you wanted to write a utility to print a list of all functions in some program that reference min. Sounds like a simple task, right?
Previous Page Next Page