
David Abrahams:
I'm writing an appendix on the PP lib for the MPL book today. I think that'll demonstrate that it's possible to provide a reasonable gentle and high-level introduction without exposing too many ugly details.
That would be great!
- Fundamental PP Abstractions - Macros - Non function - Function macros - Tokens - Sequences of tokens not including un-parenthesized commas
Data structures are an important topic and their representation isn't fundamentally PP *library* specific. You might want to present the information on the representation of data structures (and simple macros like a projection operator for tuples and some sequences operations) here when you discuss fundamental PP abstractions. I would also probably discuss how to implement primitives like IF and WHILE using preprocessor macros at this point. The purpose being to show that the preprocessor is capable of significant computation. I would also emphasize that the purpose of explaining the techniques is not that people would roll their own versions, but simply to deepen their understanding of the preprocessor.
Well, if you really have a conforming C99 preprocessor, you could use Paul M's Chaos, which I think is both easier to use and *way* more efficient than the current Boost PP.
From what I know, Chaos is essentially an extended Boost.PP (meaning that Chaos is essentially a combinator library), with a single recursion backend (enabled by stricter requirements on preproprecessor conformance), which makes it more orthogonal. However, Chaos still shares many problems with Boost.PP, the main issues being that code will be highly verbose and very intricate. The verbosity and intricacy probably do not matter that much when one only performs simple repetition using the canned library macros.
-Vesa Karvonen _________________________________________________________________ Protect your PC - get McAfee.com VirusScan Online http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963

"Vesa Karvonen" <vesa_karvonen@hotmail.com> writes:
David Abrahams:
I'm writing an appendix on the PP lib for the MPL book today. I think that'll demonstrate that it's possible to provide a reasonable gentle and high-level introduction without exposing too many ugly details.
That would be great!
- Fundamental PP Abstractions - Macros - Non function - Function macros - Tokens - Sequences of tokens not including un-parenthesized commas
Data structures are an important topic and their representation isn't fundamentally PP *library* specific. You might want to present the information on the representation of data structures (and simple macros like a projection operator for tuples and some sequences operations) here when you discuss fundamental PP abstractions.
I am not even trying to cover the whole PP library in this appendix, much less the topic of PP metaprogramming in general. I am only covering the fundamental abstractions on which the PP operates in this section, not the things we can build with those. The PP doesn't know anything about data structures.
I would also probably discuss how to implement primitives like IF and WHILE using preprocessor macros at this point.
No way! That's why this is an appendix.
The purpose being to show that the preprocessor is capable of significant computation.
The high-level library operations do that very nicely, thank you.
I would also emphasize that the purpose of explaining the techniques is not that people would roll their own versions, but simply to deepen their understanding of the preprocessor.
That's for *your* book ;-)
Well, if you really have a conforming C99 preprocessor, you could use Paul M's Chaos, which I think is both easier to use and *way* more efficient than the current Boost PP.
From what I know, Chaos is essentially an extended Boost.PP (meaning that Chaos is essentially a combinator library), with a single recursion backend (enabled by stricter requirements on preproprecessor conformance), which makes it more orthogonal. However, Chaos still shares many problems with Boost.PP, the main issues being that code will be highly verbose and very intricate. The verbosity and intricacy probably do not matter that much when one only performs simple repetition using the canned library macros.
Yes, I know that Chaos is not as beautiful as Order ;-) Paul didn't implement continuations or many of the other high-level abstractions you have. On the other hand, it is efficient without having to pass around recursion depths IIUC. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
Data structures are an important topic and their representation isn't fundamentally PP *library* specific. You might want to present the information on the representation of data structures (and simple macros like a projection operator for tuples and some sequences operations) here when you discuss fundamental PP abstractions.
I am not even trying to cover the whole PP library in this appendix, much less the topic of PP metaprogramming in general. I am only covering the fundamental abstractions on which the PP operates in this section, not the things we can build with those. The PP doesn't know anything about data structures.
I would also probably discuss how to implement primitives like IF and WHILE using preprocessor macros at this point.
No way! That's why this is an appendix.
The purpose being to show that the preprocessor is capable of significant computation.
The high-level library operations do that very nicely, thank you.
I would also emphasize that the purpose of explaining the techniques is not that people would roll their own versions, but simply to deepen their understanding of the preprocessor.
That's for *your* book ;-)
... but, thanks for the suggestions. I don't mean to sound ungrateful, but I'm really trying to limit this to a small-scale practical overview of the things you need to know in order to get started with the PP library. "Understanding the preprocessor and PP metaprogramming" is beyond the scope of the book. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

-----Original Message----- [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams
"Vesa Karvonen" <vesa_karvonen@hotmail.com> writes:
- Fundamental PP Abstractions - Macros - Non function - Function macros - Tokens - Sequences of tokens not including un-parenthesized commas
To the macro expansion mechanism, there are two main categories of preprocessing tokens--functional and non-functional. The functional preprocessing tokens are comma and the left and right parentheses. All others are non-functional (as input to macros). You have to be careful whenever you pass preprocessing tokens that are "functional" as arguments because they can have syntactic/semantic effect. Also note that an unmatched parenthesis can be considered pathological input. It is only possible to pass such a token by the use of a macro expansion, as in MACRO(LPAREN()). Unmatched parentheses in particular should *never* be passed to pp-lib primitives.
Data structures are an important topic and their representation isn't fundamentally PP *library* specific. You might want to present the information on the representation of data structures (and simple macros like a projection operator for tuples and some sequences operations) here when you discuss fundamental PP abstractions.
I am not even trying to cover the whole PP library in this appendix, much less the topic of PP metaprogramming in general. I am only covering the fundamental abstractions on which the PP operates in this section, not the things we can build with those. The PP doesn't know anything about data structures.
Not general purpose data structures, no, but it has its own which are similar in some respects, but not really. You are right when you say that you can't cover the entire pp-lib. That is another book. Covering preprocessor metaprogramming in general is another (large) book beyond that.
Well, if you really have a conforming C99 preprocessor, you could use Paul M's Chaos, which I think is both easier to use and *way* more efficient than the current Boost PP.
You don't need a conforming C99 preprocessor, just a conforming C, C++, or C99 preprocessor. With variadics enabled (i.e. C99), Chaos is certainly more powerful than without, but they aren't strictly necessary to utilize Chaos.
From what I know, Chaos is essentially an extended Boost.PP (meaning that Chaos is essentially a combinator library), with a single recursion backend (enabled by stricter requirements on preproprecessor conformance),
The recursion backend in Chaos is more than capable of handling any real-world example. However, one of the things that I have on my list for version 2 is fully generic algorithms capable of having drop-in replacements for recursion backend, etc.. I haven't done it already despite the ease of such a thing because I had to stop developing code and start writing documentation or I would never stop. :)
which makes it more orthogonal. However, Chaos still
shares many problems with Boost.PP, the main issues being that code will be highly verbose and very intricate.
Chaos, in general, is not particularly verbose, only the names are verbose because of prefixing and all-caps. The verbosity of preprocessor code is also significantly lessened by things that Chaos does that the pp-lib does not--such as lazy evaluation. OTOH, algorithm definition (but not use) is indeed intricate--especially when doing complex things such as trampolining user-defined macro invocations, making exponential use of the recursion backend, supporting lambda call semantics, supporting default arguments, supporting argument remapping, etc., all at one time (which is what Chaos does). So yes, the Chaos algorithms are both complex and powerful--they are feature rich. However, simple algorithms are easy to write without the code bloat of a Boost.PP-like implementation: // interface #define REPEAT(count, macro, data) \ REPEAT_S(CHAOS_PP_STATE(), count, macro, data) \ /**/ #define REPEAT_S(s, count, macro, data) \ REPEAT_I( \ CHAOS_PP_OBSTRUCT(), CHAOS_PP_NEXT(s), \ count, macro, data \ ) \ /**/ // implementation #define REPEAT_INDIRECT() REPEAT_I #define REPEAT_I(_, s, count, macro, data) \ CHAOS_PP_EXPR_IF _(count)( \ CHAOS_PP_EXPR_S(s) _(REPEAT_INDIRECT _()( \ CHAOS_PP_OBSTRUCT _(), CHAOS_PP_NEXT(s), \ CHAOS_PP_DEC(count), macro, data \ )) \ macro _(s, CHAOS_PP_DEC(count), data) \ ) \ /**/ Is this "highly verbose"? Compared to code that has no need to simulate recursion, yes. Compared to Boost.PP's version, no. The above is also much more powerful than pp-lib version (though much less powerful than the actual Chaos version). Compared to an implementation directly implemented on top of the continuation machine... it is certainly less terse, but it is also much clearer and significantly less design-altering. Compared to code executed by an interpreter such as Order's front end, yes (at the cost of a significant performance hit for non-trivial problems). Further, the purpose of abstractions is to avoid the need for users to implement such things. However, if a user wants to take that step--for the purposes of raw speed or just interest--Chaos offers all the low-level tools necessary to achieve it.
The verbosity and intricacy
probably do not matter that much when one only performs simple repetition using the canned library macros.
Yes, I know that Chaos is not as beautiful as Order ;-)
Chaos has far more low-level components than Order--and is far more powerful in total. Order itself can be implemented with Chaos, but not vice-versa. (Further, Order has to choose between providing beauty and safety regarding its use of unprefixed names. The safe approach has to use "8x" (or similar) prefixed names and hide them with emacs scripts--which is not much different than Chaos and "CHAOS_PP_". The unsafe approach effectively assumes ownership of a bunch of unprefixed names.)
Paul didn't implement continuations or many of the other high-level abstractions you have.
Chaos actually does have a continuation machine, similar to the one in Order. (The original implementation was indeed Vesa's.) Chaos also has different forms of higher-level abstractions as well as low-level primitives. Chaos' primary purpose (other than as my own idealistic implementation) is to generate source code, not provide a programming language. Of course, the result is like a programming language in the sense that it is utterly different from regular C or C++ programming with different techniques and idioms. However, the purpose is still only to generate the real language underneath. Chaos also has a fundamentally different point of view. Chaos, as opposed to Order, intentionally encourages better understanding of the actual language being used (which is not Chaos, but the preprocessor) rather than trying to hide it as much as possible. Completely hiding the nature of the interpreter is impossible and many times the ability to work at a "lower-level" is necessary. That isn't to say that both points of view aren't valid, they are just different. For example, Order and Chaos can invoke each other--meaning that they aren't mutually exclusive.
On the other hand, it is efficient without having to pass around recursion depths IIUC.
It is fairly efficient, but it isn't as efficient as possible--primarily because the algorithms in Chaos are full-featured. However, Chaos can be used to produce the most efficient possible implementation--which sometimes means (depending on the nature of the problem to be solved) direct use of the continuation machine or recursion backend. Regards, Paul Mensonides

"Paul Mensonides" <pmenso57@comcast.net> writes:
-----Original Message----- [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams
"Vesa Karvonen" <vesa_karvonen@hotmail.com> writes:
- Fundamental PP Abstractions - Macros - Non function - Function macros - Tokens - Sequences of tokens not including un-parenthesized commas
To the macro expansion mechanism, there are two main categories of preprocessing tokens--functional and non-functional.
Yeah I know, but I would never use those terms; too easily confused with function-like and object-like macros.
The functional preprocessing tokens are comma and the left and right parentheses. All others are non-functional (as input to macros). You have to be careful whenever you pass preprocessing tokens that are "functional" as arguments because they can have syntactic/semantic effect. Also note that an unmatched parenthesis can be considered pathological input. It is only possible to pass such a token by the use of a macro expansion, as in MACRO(LPAREN()). Unmatched parentheses in particular should *never* be passed to pp-lib primitives.
Even via LPAREN()? -- not that I'm going to reveal these details to people. I'm just telling them that unmatched parens can never be macro arguments. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of David Abrahams
To the macro expansion mechanism, there are two main categories of preprocessing tokens--functional and non-functional.
Yeah I know, but I would never use those terms; too easily confused with function-like and object-like macros.
Yeah, maybe preprocessing tokens that have syntactic/semantic effect.
The functional preprocessing tokens are comma and the left and right parentheses. All others are non-functional (as input to macros). You have to be careful whenever you pass preprocessing tokens that are "functional" as arguments because they can have syntactic/semantic effect. Also note that an unmatched parenthesis can be considered pathological input. It is only possible to pass such a token by the use of a macro expansion, as in MACRO(LPAREN()). Unmatched parentheses in particular should *never* be passed to pp-lib primitives.
Even via LPAREN()? -- not that I'm going to reveal these details to people. I'm just telling them that unmatched parens can never be macro arguments.
LPAREN() can be used to create a left parentheses, and thus can be used to pass an unmatched left parentheses to a macro. That indirection is the only way to do that. However, it is inherently dangerous because the "argument-ness" of it cannot be preserved--it interferes: #define LPAREN() ( #define A(x) x #define B(x) A(x) A(LPAREN()) // okay, expands to: ( B(LPAREN()) // error: unmatched parenthesis However, you can pass the macro name LPAREN itself as as argument, provided it isn't later invoked in a context which would cause the above situation internally. There are valid reasons to programmatically create left and right parentheses. Regards, Paul Mensonides
participants (3)
-
David Abrahams
-
Paul Mensonides
-
Vesa Karvonen