Primitives

| Home | Libraries | People | FAQ | More

## Primitives

Actors are composed to create more complex actors in a tree-like hierarchy. The primitives are atomic entities that are like the leaves in the tree. Phoenix is extensible. New primitives can be added anytime. Right out of the box, there are only a few primitives. This section shall deal with these preset primitives.

### Arguments

    #include <boost/spirit/home/phoenix/core/argument.hpp>

We use an instance of:

    actor<argument<N> >

to represent the Nth function argument. The argument placeholder acts as an imaginary data-bin where a function argument will be placed.

## Predefined Arguments

There are a few predefined instances of `actor<argument<N> >` named `arg1`..`argN`, and its BLL counterpart `_1`..`_N`. (where N is a predefined maximum).

Here are some sample preset definitions of `arg1`..`argN`

    actor<argument<0> > const arg1 = argument<0>();
    actor<argument<1> > const arg2 = argument<1>();
    actor<argument<2> > const arg3 = argument<2>();

and its BLL `_1`..`_N` style counterparts:

    actor<argument<0> > const _1 = argument<0>();
    actor<argument<1> > const _2 = argument<1>();
    actor<argument<2> > const _3 = argument<2>();

| Note
You can set `PHOENIX_ARG_LIMIT`, the predefined maximum placeholder index. By default, `PHOENIX_ARG_LIMIT` is set to `PHOENIX_LIMIT` (See Actors).

## User Defined Arguments

When appropriate, you can define your own `argument<N>` names. For example:

    actor<argument<0> > x; // note zero based index

`x` may now be used as a parameter to a lazy function:

    add(x, 6)

which is equivalent to:

    add(arg1, 6)

## Evaluating an Argument

An argument, when evaluated, selects the Nth argument from the those passed in by the client.

For example:

    char        c = 'A';
    int         i = 123;
    const char* s = "Hello World";

    cout << arg1(c) << endl;        //  Get the 1st argument: c
    cout << arg1(i, s) << endl;     //  Get the 1st argument: i
    cout << arg2(i, s) << endl;     //  Get the 2nd argument: s

will print out:

    A
    123
    Hello World

## Extra Arguments

In C and C++, a function can have extra arguments that are not at all used by the function body itself. These extra arguments are simply ignored.

Phoenix also allows extra arguments to be passed. For example, recall our original `add` function:

    add(arg1, arg2)

We know now that partially applying this function results to a function that expects 2 arguments. However, the library is a bit more lenient and allows the caller to supply more arguments than is actually required. Thus, `add` actually allows 2 or more arguments. For instance, with:

    add(arg1, arg2)(x, y, z)

the third argument `z` is ignored. Taking this further, in-between arguments are also ignored. Example:

    add(arg1, arg5)(a, b, c, d, e)

Here, arguments b, c, and d are ignored. The function `add` takes in the first argument (`arg1`) and the fifth argument (`arg5`).

| Note
There are a few reasons why enforcing strict arity is not desireable. A case in point is the callback function. Typical callback functions provide more information than is actually needed. Lambda functions are often used as callbacks.

### Values

    #include <boost/spirit/home/phoenix/core/value.hpp>

Whenever we see a constant in a partially applied function, an

    actor<value<T> >

(where T is the type of the constant) is automatically created for us. For instance:

    add(arg1, 6)

Passing a second argument, `6`, an `actor<value<int> >` is implicitly created behind the scenes. This is also equivalent to:

    add(arg1, val(6))

`val(x)` generates an `actor<value<T> >` where `T` is the type of `x`. In most cases, there's no need to explicitly use `val`, but, as we'll see later on, there are situations where this is unavoidable.

## Evaluating a Value

Like arguments, values are also actors. As such, values can be evaluated. Invoking a value gives the value's identity. Example:

    cout << val(3)() << val("Hello World")();

prints out "3 Hello World".

### References

    #include <boost/spirit/home/phoenix/core/reference.hpp>

Values are immutable constants. Attempting to modify a value will result in a compile time error. When we want the function to modify the parameter, we use a reference instead. For instance, imagine a lazy function `add_assign`:

    void add_assign(T& x, T y) { x += y; } // pseudo code

Here, we want the first function argument, x, to be mutable. Obviously, we cannot write:

    add_assign(1, 2) // error first argument is immutable

In C++, we can pass in a reference to a variable as the first argument in our example above. Yet, by default, the library forces arguments passed to partially applied functions functions to be immutable values (see Values). To achieve our intent, we use:

    actor<reference<T> >

This is similar to `actor<value<T> >` above but instead holds a reference to a variable.

We normally don't instantiate `actor<reference<T> >` objects directly. Instead we use `ref`. For example (where `i` is an `int` variable):

    add_assign(ref(i), 2)

## Evaluating a Reference

References are actors. Hence, references can be evaluated. Such invocation gives the references's identity. Example:

    int i = 3;
    char const* s = "Hello World";
    cout << ref(i)() << ref(s)();

prints out "3 Hello World"

### Constant References

    #include <boost/spirit/home/phoenix/core/reference.hpp>

Another free function `cref(cv)` may also be used. `cref(cv)` creates an `actor<reference<T const&> >` object. This is similar to `actor<value<T> >` but when the data to be passed as argument to a function is heavy and expensive to copy by value, the `cref(cv)` offers a lighter alternative.

### Nothing

    #include <boost/spirit/home/phoenix/core/nothing.hpp>

Finally, the `actor<null_actor>` does nothing; (a "bum", if you will :-). There's a sole `actor<null_actor>` instance named "nothing". This actor is actually useful in situations where we don't want to do anything. (See for_ Statement for example).