Boost logo

Boost :

From: Markus Werle (numerical.simulation_at_[hidden])
Date: 2008-03-22 05:44:11


I may have overlooked something, but while thinking about
proto's design I was surprised by some asymmetry.

I'd like to know why this was done the way it is.

Consider two objects (type A and B are proto terminals)
A a;
B b;

The expression a + b is considered equivalent to a
function call operator+(a, b).
The corresponding type representation approximately is

expr<tag::binary_plus // I will vote for this ;-)
     ,args2<expr<tag::terminal, A>
           ,expr<tag::terminal, B> > >

This is done according to the rationale that what
binary_plus really means is domain specific.
Therefore the expression is simply tagged by
the name of the function call, while the second
argument is the typelist containing the parameters
in the same order as they appear in the expression.

Important: any information about what the function call
means is stored *outside* the expression.

Up to here I appreciate the design and IMHO this is
the most appropriate way to represent an expression
(I said that before, I know).

Now we introduce another function call - not an operator
this time, but in C++ these are equivalent.

struct fun_t {};
terminal<fun_t>::type const fun = {{}};

fun(a, b);

This is represented by something similar to

 Â tag::function
     ref_<expr<tag::terminal, args0<fun_tag> > const>
    ,expr<tag::terminal, args0<> >
    ,expr<tag::terminal, args0<> >

This is suprising. In contrast to operator+, the function fun
is treated as if it was an *operand*, not an *operator*.
The expression is not tagged by _the_ function call, but by a
global this-is-a-function-tag and the function is stored in the
argument typelist.

What fun means is context dependent, I would expect the context
to take care about what fun_t might mean, so if we want
symmetry first I'd expect a type representation similar to

    ,expr<tag::terminal, args0<...ommitted...> >
    ,expr<tag::terminal, args0<...ommitted...> >

So I wonder whether this asymmetry was introduced due to the
fact that function objects could have a state which makes them
an in-between between operator and operand ...

Can we save state in tag::function<T> then?

  tag::function<expr<tag::terminal, args0<fun_t> > >
    ,expr<tag::terminal, args0<...ommitted...> >
    ,expr<tag::terminal, args0<...ommitted...> >

I do not like that one either ...

I ask because ripping the function off the argument list
via fusion magic still looks odd to me and makes me feel
uncomfortable: Any compile time algorithm has to fork for
function calls if it is to apply an operation to the operands.

Shed some light on this, please.



Boost list run by bdawes at, gregod at, cpdaniel at, john at