"Our language has X so we do not need a preprocessor." This is a very common statement in the JavaLanguage community and elsewhere. Even BjarneStroustrup gets into the act and tells us that we don't really need #define in CeePlusPlus because we have the ConstQualifier.
-- I doubt BjarneStroustrup said this as it isn't true. There are many uses for #define besides definition of simple constants. inline code, generics, conditional compilation, code generation to name but a few. NickKeighley
Apparently, he said it in Design And Evolution Of C++. Though it was apparently limited to C's preprocessor.
--
Like GoTos and MultipleInheritance, macro preprocessors bear onus for much of the evil in the world. Is this fair? Sure enough, people have gotten themselves in a lot of trouble with these things, but we will have to see whether banning them (which prevents even sensible use) is worthwhile. Judges in law often make the point that FreedomOfSpeech has no teeth if it is interpreted in such a way that all content must be suitable for the ears and eyes of a six year old. Likewise, we may find that systematically reducing our languages is no substitute for learning how to use the fire without getting burned by it.
See DesignByContract for an example of how a preprocessor makes the implementation of DBC painless and very powerful in C++. Compare it to the work that has to be done in Java to accomplish substantially less (EfficientContractsInJava). Note, that the answer is not "use C++." The answer is "add a preprocessor or at least DBC to your language." SmalltalkLanguage programmers live with the possibility of MetaClass programming without burning themselves over and over, so it can be done.
What you are saying here is that the various facilities offered by preprocessors are not evil: but I still contend the preprocessor itself is. Assuming by "preprocessor" we mean something which manipulates program text with only the shallowest understanding of its syntax and semantics.
CeeLanguage is like that. C macros are not hygenic, they do not respect the scoping rules of the language, they are prone to SideEffects, and so forth. The problems are well known and well documented.
This doesn't mean macros are bad. Certainly it's useful to be able to specify transformations that happen at compile time rather than runtime. We need hygenic macros that operate on parse trees rather than source text. We need literal constants, templates, inline functions. We need meta-object programming. We need stuff to be integrated deeply into the language, not slapped on as an afterthought. Sorry. Naive preprocessors are evil.
-- DaveHarris
I'm just glad that I can do DesignByContract in CeePlusPlus using the preprocessor. I was not exactly glad, but I was somewhat satisfied that I was able to port a C++ class library of mine years ago to run under IntelCorporation CeeLanguage for an EmbeddedSystem using my own hand-coded VeeTable dispatching wrapped in macros.
So, to me, tools are never evil. Tool users? Well...However, I do agree wholeheartedly that it would be good if more languages supported precompilation transformations.
You can write preprocessors for any language, there doesn't have to be a specific one bound to the language. The CeePreprocessor is powerful enough to allow a capable and tasteful user to accomplish many useful things, but also allows any user to blow off assorted metaphorical limbs (in this, cpp is in synch with much of CeeLanguage; a lot of what's happened with CeePlusPlus and AnsiCee reduces this risk by moving more things like constants and generic expansions from preprocessor idioms into the language proper).
If the cpp conventions weren't so bound up with C implementations, we might have adopted something different by now, but since it's there we tend to use it. I have a fairly complete implementation of C++ exceptions based on some simple macros (from the days before one could rely on all compilers to implement them, but still in use). In hindsight, were I doing it again, I would write a custom preprocessor (a PerlLanguage or AwkLanguage script, say) instead of the macros.
There's nothing at all stopping anyone from doing the same to implement DesignByContract in JavaLanguage -- you can even code the same solution given for C++, you just have to run the cpp phase explicitly in your build scripts. Of course, it would be better if the language itself supported the idiom in a more native way.
--JimPerry
However, using a preprocessor is socially acceptable in C++. If you used one in Java, you'd probably never live it down. Your tools probably wouldn't be kind to you, either.
For those wishing for macros without chaos, you might peruse DylanLanguage. The language itself features a structured macro facility, which advocates claim is quite powerful, and safe. (p.s. I use C++, and I like the DesignByContract assert macro.) -- AlanBaljeu?
Nobody has mentioned the big problem I have with preprocessors (perhaps nobody else finds it a problem?) which is that when something goes wrong the error will be reported in the transformed text, not in the original. This gets progressively more frustrating as the transformations get more complex, on a scale of 'typical #define use' at the simple end to 'imake' (or automake) at the other. -- DanBarlow
Of course, in the CeeLanguage program itself, errors show up in the output, not in the program. Given that the preprocessor is essentially a programming language that generates a C program, it couldn't really be any other way.
I definitely feel that #include is evil, and that it should have been buried a long time ago (and replaced by a language statement that imported a real interface file). This would tremendously speed up compilation, since one could have (gasp) pre-compiled interface files. I mean, things like PascalLanguage has had for about 20 years. Yes, I know about pre-compiled headers. They are non-standard and fragile against changes in the #include order. I really don't understand why this problem with C and C++ has not been fixed. -- StephanHouben