Actors in Detail

| Home | Libraries | People | FAQ | More

### Actors in Detail

##### Actor

The main concept is the `Actor`. An `Actor` is a model of the Polymorphic Function Object concept (that can accept 0 to N arguments (where N is a predefined maximum).

An `Actor` contains a valid Phoenix Expression, a call to one of the function call operator overloads, starts the evaluation process.

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

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

    template <typename Expr>
    struct actor
    {
        template <typename Sig>
        struct result;

        typename result_of::actor<Expr>::type
        operator()() const;

        template <typename T0>
        typename result_of::actor<Expr, T0 &>::type
        operator()(T0& _0) const;

        template <typename T0>
        typename result_of::actor<Expr, T0 const &>::type
        operator()(T0 const & _0) const;

        //...
    };

Table 1.9. Actor Concept Requirements

Expression | Semantics
--- | ---
`actor(arg0, arg1, ..., argN)` | Function call operators to start the evaluation
`boost::result_of<Actor<Expr>(Arg0, Arg1, ..., ArgN)>::type` | Result of the evaluation
`result_of::actor<Expr, Arg0, Arg1, ..., ArgN>::type` | Result of the evaluation

##### Function Call Operators

There are 2*N function call operators for 0 to N arguments (N == `BOOST_PHOENIX_LIMIT`). The actor class accepts the arguments and forwards the arguments to the default evaluation action.

Additionally, there exist function call operators accepting permutations of const and non-const references. These operators are created for all N <= `BOOST_PHOENIX_PERFECT_FORWARD_LIMIT` (which defaults to 3).

| Note
Forwarding Function Problem 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`.

##### Context

On an actor function call, before calling the evaluation function, the actor created a context. This context consists of an `Environment` and an `Action` part. These contain all information necessary to evaluate the given expression.

Table 1.10. Context Concept Requirements

Expression | Semantics
--- | ---
`result_of::context<Env, Actions>::type` | Type of a Context
`context(e, a)` | A Context containing environment `e` and actions `a`
`result_of::env<Context>::type` | Type of the contained Environment
`env(ctx)` | The environment
`result_of::actions<Context>::type` | Type of the contained Actions
`actions(ctx)` | The actions

##### Environment

The Environment is a model of Random Access Sequence.

The arguments passed to the actor's function call operator are collected inside the Environment:

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

##### Actions

Actions is the part of Phoenix which are responsible for giving the actual expressions a specific behaviour. During the traversal of the Phoenix Expression Tree these actions are called whenever a specified rule in the grammar matches.

    struct actions
    {
        template <typename Rule>
        struct when;
    };

The nested `when` template is required to be Proto Primitive Transform. No worries, you don't have to learn Boost.Proto just yet! Phoenix provides some wrappers to let you define simple actions without the need to dive deep into proto.

Phoenix ships with a predefined `default_actions` class that evaluates the expressions with C++ semantics:

    struct default_actions
    {
        template <typename Rule, typename Dummy = void>
        struct when
            : proto::_default<meta_grammar>
        {};
    };

For more information on how to use the default_actions class and how to attach custom actions to the evaluation process, see more on actions.

##### Evaluation

    struct evaluator
    {
        template <typename Expr, typename Context>
        unspecified operator()(Expr &, Context &);
    };

    evaluator const eval = {};

The evaluation of a Phoenix expression is started by a call to the function call operator of `evaluator`.

The evaluator is called by the `actor` function operator overloads after the context is built up. For reference, here is a typical `actor::operator()` that accepts two arguments:

    template <typename T0, typename T1>
    typename result_of::actor<Expr, T0 &, T1 &>::type
    operator()(T0 &t0, T1 &t1) const
    {
        fusion::vector2<T0 &, T1 &> env(t0, t1);

        return eval(*this, context(env, default_actions()));
    }

##### result_of::actor

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

    namespace result_of
    {
        template <typename Expr, typename T0, typename T1>
        struct actor
        {
            typedef fusion::vector2<T0, T1>                                           env_tpe;
            typedef typename result_of::context<env_type, default_actions>::type      ctx_type
            typedef typename boost::result_of<evaluator(Expr const&, ctx_type)>::type type;
        };
    }