Inside Phoenix

| Home | Libraries | People | FAQ | More

## Inside Phoenix

This chapter explains in more detail how the library operates. The information henceforth should not be necessary to those who are interested in just using the library. However, a microscopic view might prove to be beneficial to moderate to advanced programmers who wish to extend the library.

### Actors In Detail

### Actor Concept

The main concept is the `Actor`. Actors are function objects (that can accept 0 to N arguments (where N is a predefined maximum).

| Note
You can set `PHOENIX_LIMIT`, the predefined maximum arity an actor can take. By default, `PHOENIX_LIMIT` is set to 10.

### actor template class

The `actor` template class models the `Actor` concept:

    template <typename Eval>
    struct actor : Eval
    {
        typedef Eval eval_type;

        actor();
        actor(Eval const& base);

        template <typename T0>
        explicit actor(T0 const& _0);

        template <typename T0, typename T1>
        actor(T0 const& _0, T1 const& _1);

        // more constructors

        typename apply_actor<eval_type, basic_environment<> >::type
        operator()() const;

        template <typename T0>
        typename apply_actor<eval_type, basic_environment<T0> >::type
        operator()(T0& _0) const;

        template <typename T0, typename T1>
        typename apply_actor<eval_type, basic_environment<T0, T1> >::type
        operator()(T0& _0, T1& _1) const;

        // function call operators
    };

Table 1.10. Actor Concept Requirements

Expression | Result/Semantics
--- | ---
`T::eval_type` | The actor's Eval type
`T()` | Default Constructor
`T(base)` | Constructor from Eval
`T(arg0, arg1, ..., argN)` | Pass through constructors
`x(arg0, arg1, ..., argN)` | Function call operators

### Eval Concept

The `actor` template class has a single template parameter, `Eval`, from which it derives from. While the `Actor` concept represents a function, the `Eval` concept represents the function body. The requirements for `Eval` are intentionally kept simple, to make it easy to write models of the concept. We shall see an example in the next section.

Table 1.11. Eval Concept Requirements

Expression | Result/Semantics
--- | ---
`return x.eval(env)` | Evaluates the function (see Environment below)
`T::result<Env>::type` | The return type of eval (see Environment below)

### Constructors

In addition to a default constructor and an constructor from a Eval object, there are templated (pass through) constructors for 1 to N arguments (N == `PHOENIX_LIMIT`). These constructors simply forward the arguments to the `base`.

| Note
Parametric Base Class Pattern Notice that actor derives from its template argument Eval. This is the inverse of the curiously recurring template pattern (CRTP). With the CRTP, a class, T, has a Derived template parameter that is assumed to be its subclass. The "parametric base class pattern" (PBCP), on the other hand, inverses the inheritance and makes a class, T, the derived class. Both CRTP and PBCP techniques have its pros and cons, which is outside the scope of this document. CRTP should really be renamed "parametric subclass pattern (PSCP), but again, that's another story.

### Function Call Operators

There are N function call operators for 0 to N arguments (N == `PHOENIX_LIMIT`). The actor class accepts the arguments and forwards the arguments to the actor's base `Eval` for evaluation.

| Note
Forwarding Function Problem The function call operators cannot accept non-const temporaries and literal constants. There is a known issue with current C++ called the "Forwarding Function Problem". The problem is that given an arbitrary function `F`, using current C++ language rules, one cannot create a forwarding function `FF` that transparently assumes the arguments of `F`. Disallowing non-const rvalues arguments partially solves the problem but prohibits code such as `f(1, 2, 3);`.

### Environment

On an actor function call, before calling the actor's `Eval::eval` for evaluation, the actor creates an environment. Basically, the environment packages the arguments in a tuple. The `Environment` is a concept, of which, the `basic_environment` template class is a model of.

Table 1.12. Environment Concept Requirements

Expression | Result/Semantics
--- | ---
`x.args()` | The arguments in a tie (a tuple of references)
`T::args_type` | The arguments' types in an MPL sequence
`T::tie_type` | The tie (tuple of references) type

Schematically:

Other parts of the library (e.g. the scope module) extends the `Environment` concept to hold other information such as local variables, etc.

### apply_actor

`apply_actor` is a standard MPL style metafunction that simply calls the Action's `result` nested metafunction:

    template <typename Action, typename Env>
    struct apply_actor
    {
        typedef typename Action::template result<Env>::type type;
    };

After evaluating the arguments and doing some computation, the `eval` member function returns something back to the client. To do this, the forwarding function (the actor's `operator()`) needs to know the return type of the eval member function that it is calling. For this purpose, models of `Eval` are required to provide a nested template class:

    template <typename Env>
    struct result;

This nested class provides the result type information returned by the `Eval`'s `eval` member function. The nested template class `result` should have a typedef `type` that reflects the return type of its member function `eval`.

For reference, here's a typical `actor::operator()` that accepts two arguments:

    template <typename T0, typename T1>
    typename apply_actor<eval_type, basic_environment<T0, T1> >::type
    operator()(T0& _0, T1& _1) const
    {
        return eval_type::eval(basic_environment<T0, T1>(_0, _1));
    }

### actor_result

For reasons of symmetry to the family of `actor::operator()` there is a special metafunction usable for actor result type calculation named `actor_result`. This metafunction allows us to directly to specify the types of the parameters to be passed to the `actor::operator()` function. Here's a typical `actor_result` that accepts two arguments:

    template <typename Action, typename T0, typename T1>
    struct actor_result
    {
        typedef basic_environment<T0, T1> env_type;
        typedef typename Action::template result<env_type>::type type;
    };

### Actor Example

Let us see a very simple prototypical example of an actor. This is not a toy example. This is actually part of the library. Remember the `reference`?.

First, we have a model of the `Eval` concept: the `reference`:

    template <typename T>
    struct reference
    {
        template <typename Env>
        struct result
        {
            typedef T& type;
        };

        reference(T& arg)
            : ref(arg) {}

        template <typename Env>
        T& eval(Env const&) const
        {
            return ref;
        }

        T& ref;
    };

Models of `Eval` are never created directly and its instances never exist alone. We have to wrap it inside the `actor` template class to be useful. The `ref` template function does this for us:

    template <typename T>
    actor<reference<T> > const
    ref(T& v)
    {
        return reference<T>(v);
    }

The `reference` template class conforms to the `Eval` concept. It has a nested `result` metafunction that reflects the return type of its `eval` member function, which peforms the actual function. `reference<T>` stores a reference to a `T`. Its `eval` member function simply returns the reference. It does not make use of the environment `Env`.

Pretty simple...

### Composites In Detail

We stated before that composites are actors that are composed of zero or more actors (see Composite). This is not quite accurate. The definition was sufficient at that point where we opted to keep things simple and not bury the reader with details which she might not need anyway.

Actually, a composite is a model of the `Eval` concept (more on this later). At the same time, it is also composed of 0..N (where N is a predefined maximum) `Eval` instances and an eval policy. The individual `Eval` instances are stored in a tuple.

| Note
In a sense, the original definition of "composite", more or less, will do just fine because `Eval` instances never exist alone and are always wrapped in an `actor` template class which inherits from it anyway. The resulting actor IS-AN `Eval`.

| Note
You can set `PHOENIX_COMPOSITE_LIMIT`, the predefined maximum `Eval`s (actors) a composite can take. By default, `PHOENIX_COMPOSITE_LIMIT` is set to `PHOENIX_LIMIT` (See Actors).

## composite template class

    template <typename EvalPolicy, typename EvalTuple>
    struct composite : EvalTuple
    {
        typedef EvalTuple base_type;
        typedef EvalPolicy eval_policy_type;

        template <typename Env>
        struct result
        {
            typedef implementation-defined type;
        };

        composite();
        composite(base_type const& actors);

        template <typename U0>
        composite(U0 const& _0);

        template <typename U0, typename U1>
        composite(U0 const& _0, U1 const& _1);

        // more constructors

        template <typename Env>
        typename result<Env>::type
        eval(Env const& env) const;
    };

## EvalTuple

`EvalTuple`, holds all the `Eval` instances. The `composite` template class inherits from it. In addition to a default constructor and a constructor from an `EvalTuple` object, there are templated (pass through) constructors for 1 to N arguments (again, where N == `PHOENIX_COMPOSITE_LIMIT`). These constructors simply forward the arguments to the `EvalTuple` base class.

## EvalPolicy

The composite's `eval` member function calls its `EvalPolicy`'s `eval` member function (a static member function) passing in the environment and each of its actors, in parallel. The following diagram illustrates what's happening:

Table 1.13. EvalPolicy Requirements

Expression | Result/Semantics
--- | ---
`x.eval<RT>(env, eval0, eval1, ..., evalN)` | Evaluate the composite
`T::result<Env, Eval0, Eval1, Eval2, ..., EvalN>::type` | The return type of eval

The `EvalPolicy` is expected to have a nested template class `result` which has a typedef `type` that reflects the return type of its member function `eval`. Here's a typical example of the composite's eval member function for a 2-actor composite:

    template <typename Env>
    typename result<Env>::type
    eval(Env const& env) const
    {
        typedef typename result<Env>::type return_type;
        return EvalPolicy::template
            eval<return_type>(
                env
              , get<0>(*this)   // gets the 0th element from EvalTuple
              , get<1>(*this)); // gets the 1st element from EvalTuple
    }

### Composing

Composites are never instantiated directly. Front end expression templates are used to generate the composites. Using expression templates, we implement a DSEL (Domain Specific Embedded Language) that mimicks native C++. You've seen this DSEL in action in the preceding sections. It is most evident in the Statement section.

There are some facilities in the library to make composition of composites easier. We have a set of overloaded `compose` functions and an `as_composite` metafunction. Together, these helpers make composing a breeze. We'll provide an example of a composite later to see why.

#### compose

    compose<EvalPolicy>(arg0, arg1, arg2, ..., argN);

Given an `EvalPolicy` and some arguments `arg0`...argN, returns a proper `composite`. The arguments may or may not be phoenix actors (primitives of composites). If not, the arguments are converted to actors appropriately. For example:

    compose<X>(3)

converts the argument `3` to an `actor<value<int> >(3)`.

#### as_composite

    as_composite<EvalPolicy, Arg0, Arg1, Arg2, ..., ArgN>::type

This is the metafunction counterpart of `compose`. Given an `EvalPolicy` and some argument types `Arg0`...ArgN, returns a proper `composite` type. For example:

    as_composite<X, int>::type

is the composite type of the `compose<X>(3)` expression above.

#### Composite Example

Now, let's examine an example. Again, this is not a toy example. This is actually part of the library. Remember the `while_` lazy statement? Putting together everything we've learned so far, we will present it here in its entirety (verbatim):

    struct while_eval
    {
        template <typename Env, typename Cond, typename Do>
        struct result
        {
            typedef void type;
        };

        template <typename RT, typename Env, typename Cond, typename Do>
        static void
        eval(Env const& env, Cond& cond, Do& do_)
        {
            while (cond.eval(env))
                do_.eval(env);
        }
    };

    template <typename Cond>
    struct while_gen
    {
        while_gen(Cond const& cond)
            : cond(cond) {}

        template <typename Do>
        actor<typename as_composite<while_eval, Cond, Do>::type>
        operator[](Do const& do_) const
        {
            return compose<while_eval>(cond, do_);
        }

        Cond cond;
    };

    template <typename Cond>
    while_gen<Cond>
    while_(Cond const& cond)
    {
        return while_gen<Cond>(cond);
    }

`while_eval` is an example of an `EvalPolicy`. `while_gen` and `while_` are the expression template front ends. Let's break this apart to understand what's happening. Let's start at the bottom. It's easier that way.

When you write:

    while_(cond)

we generate an instance of `while_gen<Cond>`, where `Cond` is the type of `cond`. `cond` can be an arbitrarily complex actor expression. The `while_gen` template class has an `operator[]` accepting another expression. If we write:

    while_(cond)
    [
        do_
    ]

it will generate a proper composite with the type:

    as_composite<while_eval, Cond, Do>::type

where `Cond` is the type of `cond` and `Do` is the type of `do_`. Notice how we are using phoenix's composition (`compose` and `as_composite`) mechanisms here

    template <typename Do>
    actor<typename as_composite<while_eval, Cond, Do>::type>
    operator[](Do const& do_) const
    {
        return compose<while_eval>(cond, do_);
    }

Finally, the `while_eval` does its thing:

    while (cond.eval(env))
        do_.eval(env);

`cond` and `do_`, at this point, are instances of `Eval`. `cond` and `do_` are the `Eval` elements held by the composite's `EvalTuple`. `env` is the `Environment`.

### Extending

We've shown how it is very easy to extend phoenix by writing new primitives and composites. The modular design of Phoenix makes it extremely extensible. We have seen that layer upon layer, the whole library is built on a solid foundation. There are only a few simple well designed concepts that are laid out like bricks. Overall, the library is designed to be extended. Everything above the core layer can in fact be considered just as extensions to the library. This modular design was inherited from the Spirit inline parser library.

Extension is non-intrusive. And, whenever a component or module is extended, the new extension automatically becomes a first class citizen and is automatically recognized by all modules and components in the library.