[preprocessor] BOOST_PP_IS_UNARY for Borland

I've written an implementation of BOOST_PP_IS_UNARY which works for Borland, and hopefully any other preprocessors which the current implementation doesn't. It is: #define EAT2(x,y) #define IS_UNARY_CHECK(x) ~, 1 BOOST_PP_RPAREN() \ EAT2 BOOST_PP_LPAREN() ~ #define IS_UNARY(x) IS_UNARY_1(IS_UNARY_CHECK x, 0) #define IS_UNARY_1(x, y) IS_UNARY_2(x, y) #define IS_UNARY_2(x, y) y For a non-unary argument, the expansion is simple: IS_UNARY(x) => IS_UNARY_1(IS_UNARY_CHECK x, 0) => IS_UNARY_2(IS_UNARY_CHECK x, 0) => 0 For a unary argument, it expands like this (I might have got the expansion order slightly wrong but, hopefully, this illustrates how it works): IS_UNARY((x)y) => IS_UNARY_1(IS_UNARY_CHECK(x)y), 0) => IS_UNARY_2(~, 1 BOOST_PP_RPAREN() EAT2 BOOST_PP_LPAREN() ~y, 0) => IS_UNARY_2(~, 1) EAT2(~y, 0) => 1 The same technique can be used for BOOST_PP_IS_NULLARY and BOOST_PP_IS_BINARY. So, if this is used as for borland, could these marcros be made 'public'? Also, with a full working BOOST_PP_IS_UNARY, I think it should be possible to make BOOST_PP_SEQ_NIL act as an empty sequence, if I write a patch to do that would it be accepted? Daniel

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Daniel James
I've written an implementation of BOOST_PP_IS_UNARY which works for Borland, and hopefully any other preprocessors which the current implementation doesn't. It is:
#define EAT2(x,y)
#define IS_UNARY_CHECK(x) ~, 1 BOOST_PP_RPAREN() \ EAT2 BOOST_PP_LPAREN() ~
#define IS_UNARY(x) IS_UNARY_1(IS_UNARY_CHECK x, 0) #define IS_UNARY_1(x, y) IS_UNARY_2(x, y) #define IS_UNARY_2(x, y) y
I like it, but how about instead (in the interest of reuse): #include <boost/preprocessor/detail/split.hpp> #include <boost/preprocessor/punctuation/comma.hpp> #include <boost/preprocessor/punctuation/paren.hpp> #include <boost/preprocessor/tuple/eat.hpp> #define IS_NULLARY(x) \ BOOST_PP_SPLIT(1, IS_NULLARY_C x BOOST_PP_COMMA() 0) \ /**/ #define IS_NULLARY_C() \ ~, 1 BOOST_PP_RPAREN() \ BOOST_PP_TUPLE_EAT(2) BOOST_PP_LPAREN() ~ \ /**/ #define IS_UNARY(x) IS_NULLARY(IS_UNARY_C x) #define IS_UNARY_C(x) () #define IS_BINARY(x) IS_NULLARY(IS_BINARY_C x) #define IS_BINARY_C(x, y) () Can someone try these on the IBM preprocessor and the Sun preprocessor as well?
So, if this is used as for borland, could these marcros be made 'public'?
I see no problem with adding the functionality, but the macros still cannot safely be made public. On other compilers (besides Borland), their use causes stability problems. Using something like the above doesn't help (it would actually be slightly worse) because of the reliance on intermediates in the argument--which requires that expansion order proceed as it should (which is not the case on some preprocessors).
Also, with a full working BOOST_PP_IS_UNARY, I think it should be possible to make BOOST_PP_SEQ_NIL act as an empty sequence, if I write a patch to do that would it be accepted?
It is already possible because the identifier is known. Lack of a nil sequences (until we get placemarkers) was a conscience decision. An important property of sequences is the ability to directly append. By definition, if A and B are both sequences, then A B is also a sequence. There is obviously a need for nil sequences, but for now, the use of a temporal nil is the better solution. Regards, Paul Mensonides

Paul Mensonides wrote:
I see no problem with adding the functionality, but the macros still cannot safely be made public. On other compilers (besides Borland), their use causes stability problems. Using something like the above doesn't help (it would actually be slightly worse) because of the reliance on intermediates in the argument--which requires that expansion order proceed as it should (which is not the case on some preprocessors).
That's a shame. I find it very useful.
Also, with a full working BOOST_PP_IS_UNARY, I think it should be possible to make BOOST_PP_SEQ_NIL act as an empty sequence, if I write a patch to do that would it be accepted?
It is already possible because the identifier is known.
I should have realised that, since that's how lists work.
Lack of a nil sequences (until we get placemarkers) was a conscience decision. An important property of sequences is the ability to directly append. By definition, if A and B are both sequences, then A B is also a sequence.
That makes sense. I guess my version isn't that useful then. But, it's a nice trick and I can use it in my own stuff, which will probably never work on preprocessors where BOOST_PP_IS_UNARY is unstable. thanks, Daniel

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Daniel James
I see no problem with adding the functionality, but the macros still cannot safely be made public. On other compilers (besides Borland), their use causes stability problems. Using something like
Paul Mensonides wrote: the above
doesn't help (it would actually be slightly worse) because of the reliance on intermediates in the argument--which requires that expansion order proceed as it should (which is not the case on some preprocessors).
That's a shame. I find it very useful.
I know. They (and other types of detection macros) are very useful. Right now, the Borland configuration is used by the IBM preprocessor and the Sun preprocessor also. I'd like to know whether or not those macro definitions work correctly on those preprocessors before I add it. Though those macros aren't part of the public interface, they are part of the internal interface. I.e. they are used internally as if they were a public interface (though they are used carefully on some preprocessors). They are stable, and the worst thing that might happen in the future is that they will be moved to a different directory. Thus, you can use them, but beware of VC and versions of MWCW prior to v9. They in particular have severe problems with expansion order. E.g. VC will even fail this test: #define IM 1, 2 #define A(im) B(im) #define B(x, y) x + y A(IM)
Also, with a full working BOOST_PP_IS_UNARY, I think it should be possible to make BOOST_PP_SEQ_NIL act as an empty sequence, if I write a patch to do that would it be accepted?
It is already possible because the identifier is known.
I should have realised that, since that's how lists work.
Exactly. Note, BTW, that Borland's non-integrated command line preprocessor (i.e. not the compiler itself in preprocess-only mode) is a pretty good preprocessor. It doesn't have the weird identifier-splicing bug that makes the straightforward version of IS_UNARY (etc.) not work. Last time I checked, it can even handle Chaos.
Lack of a nil sequences (until we get placemarkers) was a conscience decision. An important property of sequences is the ability to directly append. By definition, if A and B are both sequences, then A B is also a sequence.
That makes sense. I guess my version isn't that useful then.
It isn't that it isn't useful, because it is. Lack of nil is an important limitation of sequences. However, having an alternate representation (such as SEQ_NIL or even ~) leads to algorithmic code that constantly checks for nil when building a sequence--either with a predicate (like IS_CONS or IS_NIL) or indirectly though a CONS that is does that test.
But, it's a nice trick and I can use it in my own stuff, which will probably never work on preprocessors where BOOST_PP_IS_UNARY is unstable.
Regarding the instability: the macro itself is stable, but the input is not which can foul up the internals. The library itself does a ton of extra scaffolding to force expansion order when it is important (for VC and MWCW < 9) it does this globally across the entire library. However, that scaffolding does not exist in user code (nor should it have to if at all possible), and IS_UNARY (etc.) cannot force an arbitrary amount of expansion to account for it. You'd be surprise how much stuff doesn't expand when it should on those preprocessors that happens to get picked up later. (You might have guessed that I really really hate those preprocessors.) Regards, Paul Mensonides

Paul Mensonides wrote:
Note, BTW, that Borland's non-integrated command line preprocessor (i.e. not the compiler itself in preprocess-only mode) is a pretty good preprocessor. It doesn't have the weird identifier-splicing bug that makes the straightforward version of IS_UNARY (etc.) not work. Last time I checked, it can even handle Chaos.
That caught me out once, I thought I had some macros working on Borland, but it was only working on the separate preprocessor.
Regarding the instability: the macro itself is stable, but the input is not which can foul up the internals. The library itself does a ton of extra scaffolding to force expansion order when it is important (for VC and MWCW < 9) it does this globally across the entire library. However, that scaffolding does not exist in user code (nor should it have to if at all possible), and IS_UNARY (etc.) cannot force an arbitrary amount of expansion to account for it. You'd be surprise how much stuff doesn't expand when it should on those preprocessors that happens to get picked up later.
Thanks for the explanation. It'll be a big help.
(You might have guessed that I really really hate those preprocessors.)
I can understand, I've seen the workarounds. I'm really impressed by how well the boost preprocessor library hides all of this. Daniel
participants (2)
-
Daniel James
-
Paul Mensonides