Boost logo

Boost :

Subject: Re: [boost] [preprocessor] Sequences vs. All Other Data Structures
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2012-04-22 05:33:19


On Sun, 22 Apr 2012 00:09:52 -0700, paul Fultz wrote:

> I understand that Chaos won't implement workarounds. I was thinking more
> of forking chaos, and trying to implement it in msvc. Would that be a
> possibility? And with your knowledge of Chaos's implementation and msvc
> limitations, do you even think that it would even be remotely feasible?

I don't think it's feasible. You *might* be able to emulate the
base interface over a completely separate (and much larger)
implementation. However, you won't be able to emulate the extensibility
model. For example, one of the defining things about Chaos is its ability
to generalize recursion (not referring to the sequence tricks that I
started this thread with). That generalization of recursion reaches into
client code. This model is quite different from (e.g.) the Boost pp-lib
where you have

  end-user -> boost-pp

This end-user might be a library, of course, and there may be a few
exceptions, but not really. The pp-lib itself is incapable of reusing
itself properly--how many times have there been complaints that algorithm
XYZ is not reentrant? Essentially, the boost-pp model is just not
extensible.

In Chaos, however, you have a model that is more like regular software:

  end-user -> { chaos-pp 3rd-party-library }
  3rd-party-library -> { chaos-pp 3rd-party-library }

The closest reference to the core language that either boost-pp or chaos-
pp makes is probably ENUM_PARAMS. However, there is a huge "unexplored"
area between the relatively low-level preprocessor libraries like boost-pp
and chaos-pp and the higher level semantics of the core language with
scenarios that are more specific than the low-level libraries but still
library-izable (!!).

For example, any powerset contains the nil set. However, one doesn't
always want it in the result. So, I might do:

#define A(s, seq) \
    CHAOS_PP_INLINE_WHEN(CHAOS_PP_SEQ_IS_CONS(seq))( \
        /* DO WHATEVER */ \
    ) \
    /**/

CHAOS_PP_EXPR(CHAOS_PP_SEQ_FOR_EACH(
    A, POWERSET(SEQ)
))

However, even though /* DO WHATEVER */ may not be generalizable, the
predication is. So, I might instead do something like:

#define FILTER(s, e, p, ...) \
    FILTER_I( \
        CHAOS_PP_OBSTRUCT(), CHAOS_PP_NEXT(s), e, p, \
        CHAOS_PP_NON_OPTIONAL(__VA_ARGS__), \
        CHAOS_PP_PACK_OPTIONAL(__VA_ARGS__) \
    ) \
    /**/
#define FILTER_I(_, s, e, p, m, pack) \
    CHAOS_PP_INLINE_WHEN _( \
        CHAOS_PP_CALL(p)()(s, p, e CHAOS_PP_EXPOSE(pack)) \
    )( \
        CHAOS_PP_CALL(m)()(s, m, e CHAOS_PP_EXPOSE(pack)) \
    ) \
    /**/

#define A(s, seq) /* DO WHATEVER */

CHAOS_PP_EXPR(CHAOS_PP_SEQ_FOR_EACH(
    FILTER, POWERSET(SEQ), CHAOS_PP_SEQ_IS_CONS_(CHAOS_PP_ARG(1)), A
))

This isn't perfect--it doesn't deal with non-unary sequences, for
example. However, that could be accomplished with similar sorts of
chaining.

Now, in the above, SEQ_FOR_EACH is reentrant, the predicate called by
FILTER can use FILTER, and thus FILTER is reentrant. The macro, A can be
made reentrant (if necessary). And all these reentrancies are bouncing
around between potentially multiple libraries and user code (let's say
CHAOS_PP_* is provided by Chaos (C), FILTER is provided by library A,
POWERSET is provided by library B (which somehow uses library A), and the
end-user (E) does the above).

This works because of the extensibility of the architecture. Emulating
the interface is one thing--which still might not be possible with MSVC.
Emulating the extensibly with MSVC, in particular, is either impossible or
difficult beyond belief.

Regards,
Paul Mensonides


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk