Hi, --------------------- Thanks for the feedback. I read them all with interest. I still don't have net access yet so pardon me if I reply scarcely. Anyway, I read some interesting wish lists. What I need to point out is that phoenix is **sooo** extensible that most of these wish list items are trivial to implement. And so... To give you another glimpse into the power of phoenix when it comes to extensibility, I hacked in less than 1 hour code that implements *TRUE* local variables in the framework. Note: Not to be confused with closures. No intrusive code was written at all and the original framework remains as is. (see sample7.cpp) --------------------- First let me start with an appetizer: for_each(c.begin(), c.end(), locals<int, char const*>(0, "...That's all\n") [ for_(loc1 = 0, loc1 < arg1, ++loc1) [ cout << loc1 << ", " ], cout << loc2 ] ); loc1 is a true local variable. Predefined are loc1..locN. Prior to evaluation, locals<int, char const*>(0, "...Bye Bye\n") creates an int local variable initialized to 0 and another char const* local variable initialized to "...That's all\n". These variables can be any type and as much as N (a predefined maximum) local variables can be declared. Examples: locals<int, double>(0, 3.6) locals<char, double, std::string>('j', 3.6, "Hello World") The initializer can be default constructed: locals<int, double>() The types can be omitted: locals(0, 3.6) locals('j', 3.6, "Hello World") The types here are inferred from the parameters. Take note though that the second is equivalent to locals<char, double, char const[N]> instead of locals<char, double, std::string>. Of course you can write: locals('j', 3.6, std::string("Hello World")) To make it explicit. The local variable's scope is the expression or statements inside the brackets following it: i.e. some_expression in: locals<types>(init)[some_expression] loc1..locN correspond to the Nth local variable declared in locals<T0...TN>. We've seen the for_ before. Obviously loc1 = 0, the for_ initializer is redundant because it is initialized already in the locals initialization. Anyway... this is just for demonstration. Perhaps it's better to use a while_(blah)[blah_blah]. --------------------- Now on to some advanced phoenix coding: *** Warning, understanding the following code requires some knowledge of the framework as written in the "inside phoenix" of the docs. *** *** Warning, also requires mastery of templates *** First, we need a special tuple duo. It *is a* tuple like the one we see in TupleT in any actor base class' eval member function. Let's call it local_tuple. local_tuple should look and feel the same as a tupled-args, that's why it is derived from TupleArgsT. It has an added member though, locs. The member locs is another tuple where the local variables will be stored. locs is mutable to allow read-write access to our locals regardless of local_tuple's constness (The eval member function accepts it as a const argument). template <typename TupleArgsT, typename TupleLocsT> struct local_tuple : public TupleArgsT { typedef TupleLocsT local_vars_t; local_tuple(TupleArgsT const& args, TupleLocsT const& locs_) : TupleArgsT(args), locs(locs_) {} mutable TupleLocsT locs; }; ******************** Here, we will write our primitive local_var class. It looks so curiously like the argument class in primitives.hpp. local_var provides access to the Nth local variable packed in the tuple duo local_tuple above. Note that the member function eval expects a local_tuple argument. Otherwise the expression 'tuple.locs' will fail (compile-time error). local_var primitives only work within the context of a locals_composite (see below). template <int N> struct local_var { template <typename TupleT> struct result { typedef typename local_var_result<N, TupleT>::type type; }; template <typename TupleT> typename local_var_result<N, TupleT>::type eval(TupleT const& tuple) const { return tuple.locs[tuple_index<N>()]; } }; local_var_result is a return type computer. Given a constant integer N and a tuple, get the Nth local variable type. If TupleT is not really a local_tuple, we just return nil_t. Otherwise we get the Nth local variable type. template <int N, typename TupleT> struct local_var_result { typedef nil_t type; }; This one above, is for the generic case. Our local_var works only with local_tuple types so the one above just returns nil_t. template <int N, typename TupleArgsT, typename TupleLocsT> struct local_var_result<N, local_tuple<TupleArgsT, TupleLocsT> > { typedef typename tuple_element<N, TupleLocsT>::type& type; }; This one is a specialization for local_tuple types. Here, we get the Nth tuple_element of local_tuple::local_vars_t (or TupleLocsT). Let us also provide some predefined local_var actors: actor<local_var<0> > const loc1 = local_var<0>(); actor<local_var<1> > const loc2 = local_var<1>(); actor<local_var<2> > const loc3 = local_var<2>(); actor<local_var<3> > const loc4 = local_var<3>(); actor<local_var<4> > const loc5 = local_var<4>(); ******************** Now let's write a composite. Let's call it locals_composite. This class encapsulates an actor and some local variable initializers packed in a tuple. template <typename ActorT, typename LocsT> struct locals_composite { typedef locals_composite<ActorT, LocsT> self_t; template <typename TupleT> struct result { typedef typename actor_result<ActorT, TupleT>::type type; }; locals_composite(ActorT const& actor_, LocsT const& locals_) : actor(actor_), locals(locals_) {} template <typename TupleT> typename actor_result<ActorT, TupleT>::type eval(TupleT const& args) const { return actor.eval(local_tuple<TupleT, LocsT>(args, locals)); } ActorT actor; LocsT locals; }; Let's take this one at a time: typedef locals_composite<ActorT, LocsT> self_t; Our self type. template <typename TupleT> struct result { typedef typename actor_result<ActorT, TupleT>::type type; }; The result of our eval function is just the actor_result of our embedded actor. locals_composite(ActorT const& actor_, LocsT const& locals_) : actor(actor_), locals(locals_) {} our constructor. Just stuff the input to our member vars. template <typename TupleT> typename actor_result<ActorT, TupleT>::type eval(TupleT const& args) const { actor.eval(local_tuple<TupleT, LocsT>(args, locals)); } Here is our eval member function. locals_composite is just like a proxy and delegates the actual evaluation to the actor. The actor does the actual work. In the eval member function, before invoking the embedded actor's eval member function, we first stuff an instance of our locals and bundle both 'args' and 'locals' in a local_tuple. This local_tuple instance is created in the stack initializing it with our locals member. We then pass this local_tuple instance as an argument to the actor's eval member function. ******************** Of course this wouldn't be complete if we didn't supply a generator for our composite. We have a 2-step generator. Here is the second. The first will be given last (;-)... template <typename LocsT> struct locals_gen { locals_gen(LocsT const& locals_) : locals(locals_) {} template <typename ActorT> actor<locals_composite<typename as_actor<ActorT>::type, LocsT> > operator[](ActorT const& actor) { return locals_composite<typename as_actor<ActorT>::type, LocsT> (as_actor<ActorT>::convert(actor), locals); } LocsT locals; }; One at a time: locals_gen(LocsT const& locals_) : locals(locals_) {} At construction time, this class is given some local var-initializers packed in a tuple. We just store this for later. actor<locals_composite<typename as_actor<ActorT>::type, LocsT> > operator[](ActorT const& actor) The operator[] of this class creates the actual locals_composite given an actor. This is responsible for the construct locals<types>[actor]. As usual, we convert the input to a valid actor in: as_actor<ActorT>::type and its corresponding: as_actor<ActorT>::convert(actor) Finally, we must provide our front end generators. These generators are overloaded for 1..N local variables. Only 1-local and 2-local versions are provided. The others are straightforward variations. template <typename T0> inline locals_gen<tuple<T0> > locals(T0 const& _0) { typedef tuple<T0> tuple_t; return locals_gen<tuple_t>(tuple_t(_0)); } template <typename T0, typename T1> inline locals_gen<tuple<T0, T1> > locals(T0 const& _0, T1 const& _1) { typedef tuple<T0, T1> tuple_t; return locals_gen<tuple_t>(tuple_t(_0, _1)); } So, when we see the expression: locals<int>(0) [ blah ] Here's what happens: template <typename T0> inline locals_gen<tuple<T0> > locals(T0 const& _0) is called first. locals<int>(0) generates another generator locals_gen. locals_gen has a member operator[] that returns an actor<locals_composite<..blah..> >: template <typename ActorT> actor<locals_composite<typename as_actor<ActorT>::type, LocsT> > operator[](ActorT const& actor) Thus, the final result is an actor<locals_composite<..blah..> >. This concludes the front-end. Now on to the back-end. STL's for_each calls the actor<locals_composite> passing in the container's element as arg1. Doing so, locals_composite's eval is called: eval(TupleT const& args) const { actor.eval(local_tuple<TupleT, LocsT>(args, locals)); } This eval member function bundles the args passed in plus an instance of our local variables 'locals'. This is then passed to its actor. The actor in our example just so happens to be a for_composite (see statement.hpp). for_composite does its usual stuff. At some point, the primitive 'loc1' is evaluated. 'loc1' extracts the actual local variable from the tupled arguments plus locals passed in by the locals_composite. --------------------- Now, it took me much longer to write this than the code itself. Have fun! Some more talk :-) ** cout_, endl_ etc. can indeed be made available to all platforms. ** I am aware of the importance of switch_ and case_ for completeness. I am just not sure yet on how the final syntax would be. As you can see above, implementation is easy. Designing the interface is difficult. BTW you might see that the above code is useful. It is. I am just not sure yet if it is the best syntax for locals. ** Adapting closures is as trivial as above. I am not sure yet whether to: 1) migrate spirit-closures to phoenix (where it really should be) 2) adapt spirit-closures to phoenix (temporarily) ** There's ***sooo*** much you can do with phoenix. It's really very tempting to play with it and extend it to extremes. I'd rather resist the temptation. 1) I want to go back to Spirit coding :-) 2) The architecture is open like STL. Purist as I am, I prefer packaging an extremely cohesive set of features, no more, no less. Keep it as simple as possible, but not simpler :-) People may then contribute add-ons as they wish. These add-ons will be in the form of external modules. Not unless a certain feature is simple and useful enough to many, then, it may migrate to the core. In fact, I'm not even sure if the special_ops.hpp (std adapters) should be there at all. ** I read Martijn's qsort challenge with interest. This is certainly possible. However, I doubt its usefulness other than for demonstration. Remember that lazy-operators and lazy statements have some overhead. The operators-statements part of phoenix, although quite interesting, should be used sparingly. I am not sure yet how much overhead there is. I invite people to do some benchmarks for lazy-statements/operators vs. lazy-functions. I certainly need that in the docs. There are surely some space/time overhead. I am not sure though how the compiler optimizer will handle that. (BTW, hey, LL has the same overhead). ** The main center-stage, IMO, should be the rank-2 polymorphic lazy functions. In conjunction with well-placed lazy-ops and lazy- statements, lazy-functions are very powerful workhorses. An interesting extension might be to write lazy-function versions of the STL algorithms that just forwards to the STL stuff. Now that would be truly useful! (and trivial :) Example: struct for_each_impl { template <typename BeginT, typename EndT, typename DoT> struct result { typedef DoT type; }; template <typename IterT, typename DoT> DoT operator()(IterT first, IterT last, DoT do_) const { return std::for_each(first, last, do_); } }; function<for_each_impl> for_each_; Regards, --Joel PS> As for the other messages, pardon me. I will try to catch up as soon as I get online again. Cheers....