
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Dave Steffen
I agree that macros are code writers, no arguments there.
I also agree that macros are not part of the C++ syntax model at all. No question. From the C++ point of view, macros are some sort of alien life form that shows up, does something that's hopefully useful and correct (but might not be), and then goes away, leaving a trail of slime in its wake. In the presence of macros, don't go after the cat. :-) :-)
I disagree with just about all of this except the first two sentences. There is nothing wrong with macros. There is something wrong with trying to make macros look like non-macros.
They're so unpleasant that Bjarne "Our Founder" Stroustrup has always encouraged minimizing the use of the preprocessor,
And Bjarne is wrong, IMO. How much the preprocessor should be used is entirely dictated by whether preprocessor use is a better solution than the alternatives. It isn't even a case of "last resort".
restricting its use to the #include thing, and IIRC would like to come up with a language extension eliminating even that. (Isn't there a "modules" language extension being discussed for C++0X?) A preprocessorless C++ would certainly be A Good Thing (that may never happen, but that's a different discussion).
That would be a terrible thing. Having a standard source code manipulation tool that is above the syntax of the language is incredibly useful.
I would claim that while macros are indeed aliens that sometimes display unpleasant behavior (e.g. unreadable error messages when misused),
Trivially fixed by preprocessing in a separate pass--which is something you can't do with templates.
one _can_ assign some sort of C++ syntactic meaning to their use.
But we shouldn't. We should assign syntactic meaning to what they result in. FOREACH is not a looping construct. It is a looping construct *writer*, and that is exactly how it should be viewed. The point being, what a macro expands to should always be a fundamental part of the interface of a macro. The "return value" of a macro is code.
For example: the FOREACH macro is clearly meant to take the syntactic place of "for (bim; bam; boom++)", and anywhere you can put that, you can put an appropriate FOREACH. This is an good example of your "macro only accomplishes *part* of its function--it only generates *part* of the code", and you follow it with the rest.
This is an example of where it is necessary, or, at least, superior to do so. Not because of the resulting syntax, but because of the caveats in the syntax if it was the other way (e.g. you'd have to encode open commas).
Now: I would argue strongly that, to the extent that a macro is intented to be used in some syntactic C++ context, it should do its best to fit in to that context.
I couldn't disagree with this mentality more. A macro should *never* be designed to "fit into some syntactic C++ context". It may be defined to fit into some C++ _semantic_ context, but only the result of a macro should be defined to fit into a syntactic context. The concept of macros as an underlying C++ syntactic construct is pure evil.
BOOST_PARAMETER_KEYWORD(tag_namespace, name) should mandate a semicolon, just as function declarations and class definitions do.
Function definitions don't, and not all member functions should be implicitly marked as inline by being defined inside a class definition.
Yes: "Macros are not functions. Invocations are are not expressions, they are not statements, and they are not declarations." But they are going to sit side-by-side with our expressions, statements, and declarations.
No, they sit side-by-side, create, and interleave with our expressions, statements, and declarations.
I think you want to intentionally design macros _not_ to conform to the syntax of their intended use, so that anyone who uses them sees, loud and clear, WARNING: ALIEN MACRO INVOCATION. THIS IS NOT C++. DO NOT GO AFTER SHIP'S CAT.
I have a problem with several prevailing viewpoints. One of them is that macros are evil. The reason that this is a prevailing viewpoint is precisely because people keep trying to make them fit into the syntax model, instead viewing them as a separate syntax model that is overlaid. Nearly all macro-related problems stem from this attempted facade.
I don't think that helps. I don't think it is useful to intentionally build libraries where, from the user's point of view, some things obey C++ grammar and some things arbitrarily don't.
It isn't arbitrary. Some things are written in the language understood by the preprocessor. All constructs written in that language should be assumed by users *not* to fit into the C++ grammar.
Yes, those that don't obey the usual syntax make me think "Ah yes, that's a macro, am I using it correctly?" But we already do that because of the ALL_CAPS_MACRO convention, which flags things that C++ programmers quickly learn to approach with caution. And if the correct syntax is unclear ("Do I follow this macro with a semicolon, statement block, or mystic runes?"), isn't it more likely we'll screw it up?
That is what documentation is for, which is no different than any other construct. The syntax of a function call (a real function call) says almost nothing about how the function can be used and what it does. It only shows how a function call can be syntactically formed. The rest is the semantic effect of the function. With a macro, what the invocation results in is the semantic effect of the macro--which should be documented if the macro is an interface. I.e. the semantic effect of a macro *is* the syntactic effect on the program, and it should be documented from that viewpoint. The semantic intention of the resulting code should also be documented (obviously). Regards, Paul Mensonides