Boost logo

Boost Users :

Subject: Re: [Boost-users] [Proto?][Phoenix?] : Advice on creating lazy data structures
From: Eric Niebler (eric_at_[hidden])
Date: 2010-03-30 01:22:45


On 3/30/2010 2:02 PM, Manjunath Kudlur wrote:
> With Phoenix or lambda-like DSELs implemented with Proto, it is easy
> to implement stuff when the expected actual parameters to the lambda
> expressions are primitive types. When I want to pass arbitrary types
> to the lambda expression and manipulate it in the lambda expression,
> things become complex. For example, consider the following function :
>
> struct point {
> float x;
> float y;
> };
>
> float sum(point p) {
> return p.x+p.y;
> }
>
> If I want to have a lazy version of this function, I cannot simply do
> (arg1.x + arg1.y)(p). I have to implement functions that return Proto
> or Phoenix expressions and use it in the language. In the above case,
> it would look something like (point_get_x_(arg1) +
> point_get_y_(arg2))(p). So for every type I want to support in the
> DSEL, I have to implement lazy versions of functions to get and set
> the type members, or call some methods. In other words, the language
> has to be aware of all the data types that can be used with it.
<snip>

Not necessarily. These these can be added to your DSEL post-hoc, and
there are some fun games you can play with proto's operator->*. Consider
the following program:

   #include <cassert>
   #include <boost/proto/proto.hpp>
   namespace proto = boost::proto;

   struct point
   {
     int x, y;
   };

   proto::terminal<int point::*>::type x = {&point::x};
   proto::terminal<int point::*>::type y = {&point::y};

   struct arg_ {};
   proto::terminal<arg_>::type arg = {{}};

   struct micro_lambda
     : proto::or_<
           proto::when<
               proto::terminal<arg_>
             , proto::_state
>
         , proto::otherwise<
               proto::_default<micro_lambda>
>
>
   {} eval;

   int main()
   {
       point p = {2,4};
       int r = eval( arg->*x + arg->*y, p );
       assert( r == p.x + p.y );
   }

You can't overload operator dot (.), but proto makes up for it by
automatically interpreting ->* as if it were dot. Proto evaluates the
LHS and RHS, and as long as the RHS is something like a data member
pointer or member function pointer that can be applied to the LHS, it
all Just Works.

It works with mutation through the data member pointer, too:

       eval( arg->*x *= 21, p );
       assert( p.x == 42 );

HTH,

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net