
Noah Stein wrote:
Eric,
I spent a few hours the other week trying to convert my last matrix-vector class library over to proto. It implemented expression trees, but I’d never gotten around to adding some features that proto should make much, much easier to implement such as expression optimization. I figured it would be a good way to experiment with the library to review. I eventually gave up on refactoring my class towards proto and instead tried refactoring your lazy_vector example towards my class. It's raised some questions/points. I'll illustrate with questions that are based on your lazy_vector example.
1) lazy_vector seemed like it could derive from lazy_vector_expr in CRTP fashion. I figured your use of std::vector<T> as the terminal type was just to make initialization easier;
??? It's a lazy_vector. My use of std::vector<> has nothing to do with initialization. It's to hold a vector of elements.
however, using CRTP fails to compile. Did I miss this in the documentation or is it not explicitly mentioned?
What failed to compile? Can you show me the code?
2) How can I handle scalar values transparently? My attempts to accept "v1=v2*5" have failed. I can't get the 5 to implicitly construct into a scalar_vector type I have defined. I had that working in my old one, but I can't seem to figure out the correct way of setting that up in proto.
In proto, literals like 5 are converted to terminal<int>::type by default. It sounds like what you want is for int terminals to be treated as a vector of scalars. There are a couple of ways to approach this. 1) At some point, you'll need to evaluate the expression, perhaps with proto::eval() and a custom context class. In your context, you can add a handler for int terminals and treat them like scalar vectors. This is what I would do. 2) Before you evaluate an expression that may contain int terminals, you can apply a proto transform that replaces all int terminals with scalar vectors. This is probably not the ideal solution for you, unless you need to do other transforms, too (like expression optimization). 3) You can cause int terminals to be converted into scalar vectors on expression construction by using a custom generator. Think of a generator as a very simple transform that is applied to every new expression that proto creates for you. In the lazy_vector example, the lazy_vector_domain is defined like this: // Tell proto that in the lazy_vector_domain, all // expressions should be wrapped in laxy_vector_expr<> struct lazy_vector_domain : proto::domain< proto::generator<lazy_vector_expr> , LazyVectorGrammar > {}; proto::generator<> is a simple generator that takes any expression type and wraps it in lazy_vector_expr<>. You could write one that first turns scalar terminals into scalar vectors, and then wraps them in lazy_vector_expr<>. (3) is workable, but I would discourage it (see below). (2) is the Proto Way (tm), but might be tricky for someone who doesn't yet know transforms. (1) is also the Proto Way (tm) and might be the simplest thing to do.
3) My vector class' signature is very simple: template<typename T> class Vector : VectorExpr<terminal<T> > .
You probably mean VectorExpr<terminal<T>::type>, right?
The type T contains a number of traits defining the vector: the type of the elements, the dimension, how the data is stored. I can't figure out how to specify the terminals in my grammar. In your example, you use terminal<std::vector<_> > as your terminal. The std::vector part is unknown to me. That's my point of variation in my vector concept thus I can't know all the different types that could be used in the terminal. I tried deriving my storage classes from a common base class; however, that failed. Is there any way to encode some sort of restriction in the grammar for this situation? Right now, I'm using _, but that's clearly not a great solution.
If you have derived your storage classes from a common base, then try this to match your terminals: proto::and_< proto::terminal<_> , proto::if_< is_base_and_derived< common_base, _arg >() >
Proto looks very interesting. I was quite excited the first I saw it mentioned. There seems to be a lot of power there. I just need to figure out how to use it. You have a lot of documentation, but it seems to be attacking the problem from the opposite direction I'm approaching from, so it's been a little slow going. I hate asking questions about something I can investigate on my own, but I'd like to get far enough along that I can properly review it.
Yes, Proto comes at the problem differently than other expression template libraries, because it's not really an expression template library. It's a library for building domain-specific languages. In Proto, the expression template itself, and the operator overloads that build it, are rather incidental. The focus of Proto is what you *do* with the expression once you have it. So rather than asking, "How can I get Proto to build the type I want," you might ask, "How can I get the behavior I want from the types Proto builds." The answer for that is usually either: (a) write a context, or (b) write a transform. While you can certainly get Proto to build you the type that you want, that's not Proto's natural mode of operation. By default, Proto builds an abstract tree representing the expression, with little or no domain-specific information in it. All the domain-specific knowledge is centralized in your domain's contexts or transforms. The reason I did it this way was to facilitate cross-domain interoperability. The same expression can mean one thing in one domain and something else in a different one. That allows expressions from different domains to be intermingled freely, as with semantic actions (lambda domain) in a grammar (parser domain). Or consider the placeholder terminal _1. You would like that to mean different things to bind, lambda, spirit, karma, phoenix, xpressive, etc. If it were a proto terminal, all these libraries could use the same terminal -- it's just syntax -- and the semantics could vary by library. I hope this gets you a little farther along. -- Eric Niebler Boost Consulting www.boost-consulting.com