Giving names to formal parameters of lambda expressions: a named placeholder trick.

One thing that has always bothered me of the various boost lambda abstractions (be them compile time lambdas a-la mpl or runtime lambdas a-la Boost.Lambda, phoenix or plain bind) is that you must use non descriptive names for your argument paceholders. What I would like is to be able to declare the names of the formal parameters of my lambdas. Sure, in mpl you can have your placeholder names by typedef-ing the standard placeholders to a new name; with runtime lambdas, you can create custom objects with the same type of standard placeholders. In all those cases you still need to declare them outside of the lambda expression. While reading the Proto example "Vector: Adapting a New Terminal Type", I discovered something new about C++: you can forward declare class names inside a template parameter declaration. That is, something like this is actually possible: void foo () { int i = lambda // introduce formal parameter names [ _<class left>(), _<class right>() ] // now use them! [_<left>() + _<right>()] // actual parameters values ( 10, 20 ); } The _<...>() looks a bit clumsy, but it might be actually usable. I think that such a trick might really shine with the so called "round lambda"s; in the past I have toyed with a template class 'compose' that used the round lambda syntax for functional composition: Assume you have two polymorphic function objects types that work on ranges called 'fold' and 'reverse' (which do the obvious thing implied by their names): struct reverse_fold { template<typename Sig> struct result; template<class Range, class Init, class Op> struct result<reverse_fold(Range, Init, Op)> { private: typedef typename boost::result_of<reverse(Range)>::type reversed; public: typedef typename boost::resuld_of<fold(reversed, Init, Op)>::type type; }; template<class Range, class Init, class Op> typedef typename result<reverse_fold(Range, Init, Op)>::type operator()(Range const& range, Init i, Op op) const { return fold()(reverse()(range), i, op); } }; could be rewritten, using 'compose', as: typedef compose<fold(reverse(_1), _2, _3> reverse_fold; Which saves quite a bit of typing! (of course it works only with stateless function objects). Still the non-descriptive _N placeholders bother me. Using the named placeholder trick it would become: typedef compose< // introduce formal args names args< class range , class init , class op > // expression , fold(reverse(range), init, op) // function name
reverse_fold;
With complex expressions, this could be quite a readability improvement. Except for confirming that the above expression does actually compile (at least with gcc), I have yet to try to implement it, but I think it should be fairly easy. Comments? -- gpd

AMDG Giovanni Piero Deretta wrote:
That is, something like this is actually possible:
void foo () { int i = lambda // introduce formal parameter names [ _<class left>(), _<class right>() ] // now use them! [_<left>() + _<right>()] // actual parameters values ( 10, 20 ); }
The _<...>() looks a bit clumsy, but it might be actually usable.
I'd rather not use _. arg sound better. lambda<class left, class right>(arg<left>() + arg<right>())
Still the non-descriptive _N placeholders bother me. Using the named placeholder trick it would become:
typedef compose< // introduce formal args names args< class range , class init , class op > // expression , fold(reverse(range), init, op) // function name
reverse_fold;
With complex expressions, this could be quite a readability improvement. Except for confirming that the above expression does actually compile (at least with gcc), I have yet to try to implement it, but I think it should be fairly easy.
Comments
Wow. This is awesome. You'd probably better reference the standard (3.3.1/5) since most people will look at this and be surprised to find that it's legal. (I certainly was) In Christ, Steven Watanabe

On Sat, Mar 29, 2008 at 4:40 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Giovanni Piero Deretta wrote:
That is, something like this is actually possible:
void foo () { int i = lambda // introduce formal parameter names [ _<class left>(), _<class right>() ] // now use them! [_<left>() + _<right>()] // actual parameters values ( 10, 20 ); }
The _<...>() looks a bit clumsy, but it might be actually usable.
I'd rather not use _. arg sound better. lambda<class left, class right>(arg<left>() + arg<right>())
I've used _ to try to shorten the amount of redundant stuff as much as possible, but I agree that arg looks much better.
Still the non-descriptive _N placeholders bother me. Using the named placeholder trick it would become:
typedef compose< // introduce formal args names args< class range , class init , class op > // expression , fold(reverse(range), init, op) // function name
reverse_fold;
With complex expressions, this could be quite a readability improvement. Except for confirming that the above expression does actually compile (at least with gcc), I have yet to try to implement it, but I think it should be fairly easy.
Comments
Wow. This is awesome. You'd probably better reference the standard (3.3.1/5) since most people will look at this and be surprised to find that it's legal. (I certainly was)
Making compilers swallow this syntax won't be easy. I do not own the standard (yes, I should be ashamed :( ), but looking at the last c++0x standard, it seems that a forward declaration in a template should belong to the nearest non class namespace. Comeau online reject this (rightly, it seems): template<typename T> struct expr; void foo() { typedef expr<class A> B; } because it inject class A inside foo namespace, and thus has static linkage. This means that, unfortunately, if Comeau is right, the trick can't be used in function scope. GCC (both 4.2 and 4.3) incorrectly accepts it, because i think it puts A in the global namespace. This means that this fails with gcc: enum A {}; namespace foo { typedef expr<class A> B; } because it thinks that it is redeclaring the enum A as a class type. Comeau accepts it. -- gpd

on Fri Mar 28 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
AMDG
Giovanni Piero Deretta wrote:
That is, something like this is actually possible:
void foo () { int i = lambda // introduce formal parameter names [ _<class left>(), _<class right>() ] // now use them! [_<left>() + _<right>()] // actual parameters values ( 10, 20 ); }
The _<...>() looks a bit clumsy, but it might be actually usable.
I'd rather not use _. arg sound better. lambda<class left, class right>(arg<left>() + arg<right>())
lambda<args(class left, class right)>(arg<left>() + arg<right>()) I actually like the short nondescriptive names. It's very rare that the semantic information in a descriptive name is more valuable than the syntactic economy of the existing syntax. Just compare the above to: _1 + _2. Which do you find clearer? When the lambda expression is complicated enough that having real names is actually a win, I am usually inclined to write a separate, named function (object), anyway.
Wow. This is awesome. You'd probably better reference the standard (3.3.1/5) since most people will look at this and be surprised to find that it's legal. (I certainly was)
Not so fast. It's legal outside a function, but inside a function "class A" refers to a local class of the function, which isn't a legal template parameter. You might try the following at http://www.comeaucomputing.com/tryitout/ template <class T> struct x{}; template <class T> void f() { x<class A> y; } -- Dave Abrahams Boost Consulting http://boost-consulting.com

On Sun, Mar 30, 2008 at 11:28 PM, David Abrahams <dave@boost-consulting.com> wrote:
on Fri Mar 28 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
AMDG
Giovanni Piero Deretta wrote:
That is, something like this is actually possible:
void foo () { int i = lambda // introduce formal parameter names [ _<class left>(), _<class right>() ] // now use them! [_<left>() + _<right>()] // actual parameters values ( 10, 20 ); }
The _<...>() looks a bit clumsy, but it might be actually usable.
I'd rather not use _. arg sound better. lambda<class left, class right>(arg<left>() + arg<right>())
lambda<args(class left, class right)>(arg<left>() + arg<right>())
I actually like the short nondescriptive names. It's very rare that the semantic information in a descriptive name is more valuable than the syntactic economy of the existing syntax. Just compare the above to:
_1 + _2.
Which do you find clearer?
For simple expressions I agree 100%.
When the lambda expression is complicated enough that having real names is actually a win, I am usually inclined to write a separate, named function (object), anyway.
For boost lambda I somewhat agree. Complex expressions unfortunately become too compile time heavy. OTOH, refactoring a lambda on a separate function object is a pain if you have to figure out the result of a complex composition of polymorphic function objects (result_of helps only to a point). For example, what is the result of: filter_view(reverse_view(mapped_view(range, op)), filter) (I often find much more complex expressions in my code). Also,what about MPL? As it deals only with types, the named parameter syntax is very light, and I have found out that one can write very complex mpl expressions with very little need for refactoring.
Wow. This is awesome. You'd probably better reference the standard (3.3.1/5) since most people will look at this and be surprised to find that it's legal. (I certainly was)
Not so fast. It's legal outside a function, but inside a function
"class A"
refers to a local class of the function, which isn't a legal template parameter. You might try the following at http://www.comeaucomputing.com/tryitout/ [...]
I did (see my other message). Yes, unfortunately the trick is illegal at function scope at lest untill C++0x. Which limits a lot its usefulness. -- gpd

Giovanni Piero Deretta wrote:
OTOH, refactoring a lambda on a separate function object is a pain if you have to figure out the result of a complex composition of polymorphic function objects (result_of helps only to a point). For example, what is the result of:
filter_view(reverse_view(mapped_view(range, op)), filter)
(I often find much more complex expressions in my code).
BTW, how about this: http://tinyurl.com/23jdk6 return_of is a simple wrapper around result_of. A problem is that a function type is decayed to function pointer. Regards, -- Shunsuke Sogame

On Sun, Mar 30, 2008 at 11:18 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
OTOH, refactoring a lambda on a separate function object is a pain if you have to figure out the result of a complex composition of polymorphic function objects (result_of helps only to a point). For example, what is the result of:
filter_view(reverse_view(mapped_view(range, op)), filter)
(I often find much more complex expressions in my code).
BTW, how about this: http://tinyurl.com/23jdk6 return_of is a simple wrapper around result_of.
Ah, yes, basically recursive evaluation of result_of. I have it in my bag of tools (and as an added benefit, is boost::lambda, compatible, but I guess return_of is too); it still bothers me to have to write an expression two times, one to deduce the result_type and one to actually compute the value. And it seems that things won't improve much with decltype [1]. This is in fact the reason for my compose<> template idea: If you can't avoid writing a type expression, you might as well just write that. [1] it would be great if we also had the automatic one-line-lambda result type deduction in normal functions (and polymorphic lambdas too, but that's another story :( ). -- gpd

Giovanni Piero Deretta wrote:
This is in fact the reason for my compose<> template idea: If you can't avoid writing a type expression, you might as well just write that.
BTW, Boost.Egg has the potential to implement your compose. typedef result_of_lazy<fold>::type fold_; typedef result_of_lazy<reverse>::type reverse_; typedef return_of<fold_(reverse_(T_bll_1), T_bll_2, T_bll_3)>::type reverse_fold; A showstopper is that it is difficult to offer static-initialization way. Regards, -- Shunsuke Sogame

On Tue, Apr 1, 2008 at 3:03 AM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
This is in fact the reason for my compose<> template idea: If you can't avoid writing a type expression, you might as well just write that.
BTW, Boost.Egg has the potential to implement your compose.
typedef result_of_lazy<fold>::type fold_; typedef result_of_lazy<reverse>::type reverse_; typedef return_of<fold_(reverse_(T_bll_1), T_bll_2, T_bll_3)>::type reverse_fold;
Oh! So Egg has the functionality to make function objects directly usable in lambda expressions (without bind)??? i.e. for_each(range_of_ranges, regular(protect(std::cout << accumulate(ll::_1, 0)))) does that actually work? (for appropriate definitions of for_each and accumulate, of course). I was going to ask you to provide this functionality in egg (yes, I'm working on a review :) ) BTW, i prefer to spell 'regular(protect(...))' as 'lambda[...]'
A showstopper is that it is difficult to offer static-initialization way.
Even if I guarantee that my function objects (in this case fold and reverse) are stateless? Does using the lambda placeholders complicate things? -- gpd

Giovanni Piero Deretta wrote:
BTW, Boost.Egg has the potential to implement your compose.
typedef result_of_lazy<fold>::type fold_; typedef result_of_lazy<reverse>::type reverse_; typedef return_of<fold_(reverse_(T_bll_1), T_bll_2, T_bll_3)>::type reverse_fold;
Oh! So Egg has the functionality to make function objects directly usable in lambda expressions (without bind)??? i.e.
for_each(range_of_ranges, regular(protect(std::cout << accumulate(ll::_1, 0))))
does that actually work? (for appropriate definitions of for_each and accumulate, of course). I was going to ask you to provide this functionality in egg (yes, I'm working on a review :) )
Yes. egg::lazy/nestN makes bind/protect deprecated. I've noticed that bind/protect is a customization point. e.g. X_lazy<T_boost_bind> bb_lazy; // T_boost_bind represents boost::bind. bb_lazy(foo)(::_1, 2); In fact, implementing T_boost_bind is so difficult that Egg skips it. :-)
BTW, i prefer to spell 'regular(protect(...))' as 'lambda[...]'
What is `regular`? Is it the same as egg::regular? BTW, everything must be function-call to support result_of.
Even if I guarantee that my function objects (in this case fold and reverse) are stateless? Does using the lambda placeholders complicate things?
If fold_ is DefaultConstructible and a default-constructed one is callable, it would be: typedef static_< mpl::always< return_of<T_regular(fold_(reverse_(T_bll_1), T_bll_2, T_bll_3))>::type > > reverse_fold; I tend to hesitate to use result_of/return_of without function-calls. So your `compose` may be a candidate of yet another lambda framework. Regards, -- Shunsuke Sogame

shunsuke wrote:
If fold_ is DefaultConstructible and a default-constructed one is callable, it would be:
typedef static_< mpl::always< return_of<T_regular(fold_(reverse_(T_bll_1), T_bll_2, T_bll_3))>::type > > reverse_fold;
Sorry, this never works. T_regular was pointless. After all, Boost.Lambda bind and placeholders are not usable here. In fact, Egg secretly has its own usable placeholders, though. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 6:18 AM, shunsuke <pstade.mb@gmail.com> wrote:
shunsuke wrote:
If fold_ is DefaultConstructible and a default-constructed one is callable, it would be:
typedef static_< mpl::always< return_of<T_regular(fold_(reverse_(T_bll_1), T_bll_2, T_bll_3))>::type > > reverse_fold;
Sorry, this never works. T_regular was pointless.
May be I shouldn't have used regular, but I want a way to stop a lambda expression from being, well, a lambda expression (so that I can compose it). I'll give you my use cases: In my framework (which unfortunately I do not own), I can define a fold function like this (BTW, such a macro would be a great addition to Egg): DEFUN(fold, (range)(init)(op), *(init) ){ // you can access the argument types via range_type, init_type and op_type. // result_type here is automagically defined as result_of<fold(range_type&, init_type&, op_type&)>::type result_type result = std::accumulate(boost::begin(range), boost::end(range), init, op); return result_type; } [the syntax is shamelessly stolen from boost.parameters] This will define a function object type named 'fold' in namespace 'meta' called range and an instance of this type, also named 'fold', in namespace 'algo' (the namespace names are more or less for historical reasons and do not really make much sense; also making this work in the face of ADL is a pain). Note that the third argument of the macro defines the result type. If you prefix it with a '*', you can pass an MPL expression instead of an actual type: in this context 'init' is the same as mpl::_2 (the macro takes care to rename the placeholders as the argument types). 'defun' does automatically perfect forwarding of its arguments as you would expect, and of course is both result_of and lambda compatible. It can also automatically participate in pipelines. Finally you can use the same object as a normal function object and in lambda expressions without the need for bind: normal function (non lazy): fold(my_range, 0, plus); used in a lambda expression (the first fold is not lazy, the second is lazy): fold(my_range_of_range, 0, lambda[ fold(_2, _1, lambda[ _1 + _2]) ] ); The library uses some magic to figure out if you want a lazy fold or not. Note that if you pass a lambda expression to fold, you must always wrap it with 'protect': fold(my_range, 0, _1 + _2) ; // illegal: the whole statement is a lazy expression and is not executed! fold(my_range, 0, protect(_1 + _2)); // good, now the scope for _1 and _2 is limited. The call to 'fold' is not lazy. // same as above, but I find it more readable. Also makes the lambda result_of // compatible and 'regular' (also does perfect forwarding with old versions of // boost.lambda). fold(my_range, 0, lambda[ _1 + _2]); I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
In fact, Egg secretly has its own usable placeholders, though.
Secretly? You mean that T_bll_1 and firends are not really boost.lambda placeholder types? Or you have something else in mind? Please elaborate... [1] A reason not to have optionally lazy functions is that if you forgot to protect a lambda, the entire expression might become a big lambda expression. OTOH, except for a top level for each, I always use the result of my function objects as they are otherwise side-effect free, so such errors would be easily caught by the compiler (result type mismatch). -- gpd

Giovanni Piero Deretta wrote:
I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
I did't adopt "optionally-lazy" functions. As you show, many functions take FunctionObjects as arguments so that protect or unlambda is needed everywhere. (I always follow the rationale "one name, one functionality".) Anyway, egg::unfuse with "contains_bind_expression<FusionSeq>" trait can easily implement such a optionally-lazy adaptor.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
A functional call of `static_< always<F> >::type` is expanded to F()(a1,...,aN); If F is a function pointer type, this will clearly crash. A "regular"ized Boost.Lambda functor also will crash because of uninitialized error. After all, we need a lambda functor such that default-constructed one is callable. Egg secretly has one. (I wrote it for unit testing.) See: http://tinyurl.com/yuumdv T_bind is Egg's own binder. TT_1 is Egg's own placeholder, whereas T_bll_1 is type of boost::lambda::_1. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 6:40 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
I did't adopt "optionally-lazy" functions. As you show, many functions take FunctionObjects as arguments so that protect or unlambda is needed everywhere.
Well, as I said, the lambda[] really helps to make lambdas stand up in function calls. Also you have to wrap lambdas in 'regular' in may calls anyway so you might as wel just use lambda[]. After a while it becomes second nature, I simply use it even if it isn't strictly required.
(I always follow the rationale "one name, one functionality".)
With real lambda abstraction, you wouldn't need a different name to call a function inside a lambda expression. I was trying to approximate it as much as possible in c++. Anyways, I agree that optionally lazy functions might be confusing.
Anyway, egg::unfuse with "contains_bind_expression<FusionSeq>" trait can easily implement such a optionally-lazy adaptor.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
A functional call of `static_< always<F> >::type` is expanded to F()(a1,...,aN);
If F is a function pointer type, this will clearly crash. A "regular"ized Boost.Lambda functor also will crash because of uninitialized error. After all, we need a lambda functor such that default-constructed one is callable.
I think that we would need a way to inspect a lambda expression template and see if it is stateless (i.e. it is not closing over anything stateful). If it is stateful, static_ might abort compilation if initialized with 'stateless': static_<always<F> >::type f = stateless; // does not compile if F is not stateless. As a bonus, a regularized, stateless, boost.lambda functor will initialize itself with a default constructed lambda. Figuring out if a lambda is stateless might be non trivial :) (but, IMHO, feasible). Anyways, I see that you take great care to guarantee static initialization of stateful function objects. Do you really think this is a case that is worth supporting? What are the use cases? (for example, did you use this functionality when implementing oven?). It seems to me that it complicates a lot the interface of the library (with tons of ugly macros). I understand that this functionality is opt-in (i.e. it is there only if you want it), but I feel unconfortable. May be I'm worring too much, but I think that it really makes the docs hard to follow. -- gpd

Giovanni Piero Deretta wrote:
Anyways, I see that you take great care to guarantee static initialization of stateful function objects. Do you really think this is a case that is worth supporting? What are the use cases? (for example, did you use this functionality when implementing oven?).
It seems to me that it complicates a lot the interface of the library (with tons of ugly macros). I understand that this functionality is opt-in (i.e. it is there only if you want it), but I feel unconfortable. May be I'm worring too much, but I think that it really makes the docs hard to follow.
The ability to statically initialize global objects is pretty important. In the early days of xpressive, I got a bug report about a crash which was due to construction order of its global objects, which let to Proto's expressions-are-aggregates design. If an object must be a namespace scope -- and function objects must if they are to truly behave as regular functions -- I won't use them if they need dynamic initialization. -- Eric Niebler Boost Consulting www.boost-consulting.com

On Wed, Apr 2, 2008 at 7:16 PM, Eric Niebler <eric@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
Anyways, I see that you take great care to guarantee static initialization of stateful function objects. Do you really think this is a case that is worth supporting? What are the use cases? (for example, did you use this functionality when implementing oven?).
It seems to me that it complicates a lot the interface of the library (with tons of ugly macros). I understand that this functionality is opt-in (i.e. it is there only if you want it), but I feel unconfortable. May be I'm worring too much, but I think that it really makes the docs hard to follow.
The ability to statically initialize global objects is pretty important. In the early days of xpressive, I got a bug report about a crash which was due to construction order of its global objects, which let to Proto's expressions-are-aggregates design. If an object must be a namespace scope -- and function objects must if they are to truly behave as regular functions -- I won't use them if they need dynamic initialization.
Of course I appreciate the general benefit of statically initialized function objects (i think you and David Abrahams showed me the trick used to even have them initialized in headers). I just wanted to know if there was generally necessary to have *stateful* function objects: when the simple syntax: my_function_type f = {}; isn't enough? I.e., when you actually need to put anything in those braces? I honestly do not know. I never had this necessity, but both you and Shunsuke have certainly worked with more complex function objects than I did. -- gpd

Giovanni Piero Deretta wrote:
On Wed, Apr 2, 2008 at 6:40 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
I did't adopt "optionally-lazy" functions. As you show, many functions take FunctionObjects as arguments so that protect or unlambda is needed everywhere.
Well, as I said, the lambda[] really helps to make lambdas stand up in function calls. Also you have to wrap lambdas in 'regular' in may calls anyway so you might as wel just use lambda[]. After a while it becomes second nature, I simply use it even if it isn't strictly required.
I don't sure what lambda[] does. Why not call bll::unlambda? BTW, `regular` incurs a slight overhead, so that I didn't adopt automatic "regular"ization in Oven.
(I always follow the rationale "one name, one functionality".)
With real lambda abstraction, you wouldn't need a different name to call a function inside a lambda expression. I was trying to approximate it as much as possible in c++.
But real lambda abstraction introduces different syntax.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
A functional call of `static_< always<F> >::type` is expanded to F()(a1,...,aN);
If F is a function pointer type, this will clearly crash. A "regular"ized Boost.Lambda functor also will crash because of uninitialized error. After all, we need a lambda functor such that default-constructed one is callable.
I think that we would need a way to inspect a lambda expression template and see if it is stateless (i.e. it is not closing over anything stateful). If it is stateful, static_ might abort compilation if initialized with 'stateless':
static_<always<F> >::type f = stateless; // does not compile if F is not stateless.
It is not a problem whether or not it is stateless. The problem is whether or not Default-constructed one is callable without crash. A default-constructed, regularized Boost.Lambda functor always crashes.
Anyways, I see that you take great care to guarantee static initialization of stateful function objects. Do you really think this is a case that is worth supporting? What are the use cases?
A simple case is adapting a function-pointer.
(for example, did you use this functionality when implementing oven?).
Oven functions in namespace scope are neither stateful nor pointers, so that every function might be implemented using `static_` without complicated macros.
It seems to me that it complicates a lot the interface of the library (with tons of ugly macros). I understand that this functionality is opt-in (i.e. it is there only if you want it), but I feel unconfortable. May be I'm worring too much, but I think that it really makes the docs hard to follow.
I'm really afraid that those macros may keep users away from the library. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 9:28 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
On Wed, Apr 2, 2008 at 6:40 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
I'm not saying that egg should support optionally-lazy functions [1], it is ok if the lazy and non lazy variant have the same name. I just want to be sure it is easy to define them.
I did't adopt "optionally-lazy" functions. As you show, many functions take FunctionObjects as arguments so that protect or unlambda is needed everywhere.
Well, as I said, the lambda[] really helps to make lambdas stand up in function calls. Also you have to wrap lambdas in 'regular' in may calls anyway so you might as wel just use lambda[]. After a while it becomes second nature, I simply use it even if it isn't strictly required.
I don't sure what lambda[] does.
protect + regular basically. (or only regular if it already works as protect).
Why not call bll::unlambda?
I need 'regular' behaviour. Also the name is longer :), and I really like the square bracket syntax. When/if boost.lambda will be unified with phoenix, I'll use phoenix 'lambda' (which has exactly the same syntax plus optional support for local variables).
BTW, `regular` incurs a slight overhead, so that I didn't adopt automatic "regular"ization in Oven.
Ok. I've never used lambda in performance critical code, so I can't say. I prefer to play it safe and always regularize my lambdas.
(I always follow the rationale "one name, one functionality".)
With real lambda abstraction, you wouldn't need a different name to call a function inside a lambda expression. I was trying to approximate it as much as possible in c++.
But real lambda abstraction introduces different syntax.
Of course.
After all, Boost.Lambda bind and placeholders are not usable here.
Why? Detail please :)
A functional call of `static_< always<F> >::type` is expanded to F()(a1,...,aN);
If F is a function pointer type, this will clearly crash. A "regular"ized Boost.Lambda functor also will crash because of uninitialized error. After all, we need a lambda functor such that default-constructed one is callable.
I think that we would need a way to inspect a lambda expression template and see if it is stateless (i.e. it is not closing over anything stateful). If it is stateful, static_ might abort compilation if initialized with 'stateless':
static_<always<F> >::type f = stateless; // does not compile if F is not stateless.
It is not a problem whether or not it is stateless. The problem is whether or not Default-constructed one is callable without crash.
In theory a stateless function object should always be callable without a crash. Again, I always make my function objects stateless aggregates so I have never incurred in such problems, but I understand that you want Egg to be as general as possible.
A default-constructed, regularized Boost.Lambda functor always crashes.
Well, a regularized boost.lambda is not stateless (it has at least a boolean 'initialized' flag).
Anyways, I see that you take great care to guarantee static initialization of stateful function objects. Do you really think this is a case that is worth supporting? What are the use cases?
A simple case is adapting a function-pointer.
Hum, if you want to have guaranteed static initialization, you need to statically know the function pointer value: template<typename Sig, Sig * p> static_function_ptr { typedef typename result_of_sig<Sig>::type result_type; template<typename Args...> result_type operator()(Args.... args) { return p(args); } }; Substitute the pseudo-variadic syntax with proper preprocessor magic :).
(for example, did you use this functionality when implementing oven?).
Oven functions in namespace scope are neither stateful nor pointers, so that every function might be implemented using `static_` without complicated macros.
I thought so.
It seems to me that it complicates a lot the interface of the library (with tons of ugly macros). I understand that this functionality is opt-in (i.e. it is there only if you want it), but I feel unconfortable. May be I'm worring too much, but I think that it really makes the docs hard to follow.
I'm really afraid that those macros may keep users away from the library.
Hey, maybe it is just me, maybe others won't have any problems with them. I just find the macro based initialization ugly and unnecessary complex. IMHO what you could do is just omit it from the basic documentation and reference and add an advanced section "static initialization of stateful objects" where you show how every function object adaptor in egg has a corresponding macro that can be used to guarantee static initialization (with real-life examples/use cases), at least an user does not have to know it until it really needs it. BTW, the documentation is my major problem with egg currently (I think that it needs a much bigger walk though before going into 'reference mode'), everything else are just details. -- gpd

Giovanni Piero Deretta wrote:
Hum, if you want to have guaranteed static initialization, you need to statically know the function pointer value:
template<typename Sig, Sig * p> static_function_ptr { typedef typename result_of_sig<Sig>::type result_type;
template<typename Args...> result_type operator()(Args.... args) { return p(args); } };
Substitute the pseudo-variadic syntax with proper preprocessor magic :).
Egg secretly has the feature. See "egg/inlined.hpp".
I'm really afraid that those macros may keep users away from the library.
Hey, maybe it is just me, maybe others won't have any problems with them. I just find the macro based initialization ugly and unnecessary complex.
You expect something like this?: static_result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2({}); // static boost::result_of<T_curry2(F const &)>::type c = curry2(f); // dynamic stateless_result_of<T_curry2(F)>::type c = BOOST_EGG_STATELESS(); // for stateless one. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 11:59 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
Hum, if you want to have guaranteed static initialization, you need to statically know the function pointer value:
template<typename Sig, Sig * p> static_function_ptr { typedef typename result_of_sig<Sig>::type result_type;
template<typename Args...> result_type operator()(Args.... args) { return p(args); } };
Substitute the pseudo-variadic syntax with proper preprocessor magic :).
Egg secretly has the feature. See "egg/inlined.hpp".
Inline because it is practically the only way to get gcc to inline a function pointer :) ? Anyways, one reason less to need complex static initialization.
I'm really afraid that those macros may keep users away from the library.
Hey, maybe it is just me, maybe others won't have any problems with them. I just find the macro based initialization ugly and unnecessary complex.
You expect something like this?:
static_result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2({}); // static
Can't you use boost::result_of here? (or return_of) Also, do you have a plan for allowing complex statically initialized expressions in header files without ODR violations?
boost::result_of<T_curry2(F const &)>::type c = curry2(f); // dynamic
or egg::return_of if you want recursive evaluation.
stateless_result_of<T_curry2(F)>::type c = BOOST_EGG_STATELESS(); // for stateless one.
Why not: expression<T_curry2(F)> c = { /*just this please :) */ }; // note the missing ::type -- gpd

Giovanni Piero Deretta wrote:
Egg secretly has the feature. See "egg/inlined.hpp".
Inline because it is practically the only way to get gcc to inline a function pointer :) ?
I didn't know it!
You expect something like this?:
static_result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2({}); // static
Can't you use boost::result_of here? (or return_of)
As I mentioned, result_of needs to know whether or not an argument is lvalue or rvalue. result_of is standardized, so that I don't like to violate the law. Also, as Eric stated in Proto doc, result_of compiles slow. It seems a good idea to introduce static_result_of(Do you know a better name?). All the macros can be moved to static_result_of document section, and all the result_of_xxx<> can be removed.
Also, do you have a plan for allowing complex statically initialized expressions in header files without ODR violations?
Though BOOST_EGG_CONST does nothing for now, it has the potential to work around the ODR violation. But I hesitate to say "Any function definition requires a macro!". Anyway, I want to follow the Boost.Proto way.
boost::result_of<T_curry2(F const &)>::type c = curry2(f); // dynamic
or egg::return_of if you want recursive evaluation.
I'm not sure return_of is portable under msvc. That trivial example( http://tinyurl.com/yuumdv ) actually doesn't compile. :-(
stateless_result_of<T_curry2(F)>::type c = BOOST_EGG_STATELESS(); // for stateless one.
Why not:
expression<T_curry2(F)> c = { /*just this please :) */ }; // note the missing ::type
It seems impossible to remove ::type, because `expression` can't use inheritance so that it can be a POD. Well, 8.5.1 -14- states that "When an aggregate with static storage duration...". I think that if "an aggregate" means also "subaggregate", `{}` is not enough. Anyway, I should wait for Eric's answer. BTW, expression<T_curry2(F)>::type c = {{}}; is feasible. Regards, -- Shunsuke Sogame

On Thu, Apr 3, 2008 at 1:53 AM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
You expect something like this?:
static_result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2({}); // static
Can't you use boost::result_of here? (or return_of)
As I mentioned, result_of needs to know whether or not an argument is lvalue or rvalue. result_of is standardized, so that I don't like to violate the law.
I still do not get it though. Could you show me exactly where you think the problem is? boost::result_of<F(T)>::type will return the type of the result of 'F()(T());' right? Once you know the type, and if you are sure that the type is an aggregate, doing 'boost::result_of<F(T)>::type c = {};' should always be legal. What I'm missing?
Also, as Eric stated in Proto doc, result_of compiles slow.
Ok. Is your static_result_of faster? And if so, couldn't you just port your improvements to the basic result_of? (or there are differences that allow you to take shortcuts?).
It seems a good idea to introduce static_result_of(Do you know a better name?). All the macros can be moved to static_result_of document section, and all the result_of_xxx<> can be removed.
Ah, now I see the shortcut, of course, you put the function name directly in the xxx part! Anyways, yes, I think it would be worthwhile to rearrange the documentation this way. Also you do not need to remove all the result_of_xxx functions ,but just document all of them together with static_result_of (simply state that for every function X provided by egg, there is a result_of_ ## X that does the same of static_result_of<X()>, or whatever the semantics are).
Also, do you have a plan for allowing complex statically initialized expressions in header files without ODR violations?
Though BOOST_EGG_CONST does nothing for now, it has the potential to work around the ODR violation. But I hesitate to say "Any function definition requires a macro!".
Only if you want to put them in an header file. Just to clarify, what I do is this: template<typename Aggregate> struct instance_of { static Aggregate instance; }; template<typename Aggregate> Aggregate instance_of::instance = {}; Then I use it like this: // in an header const fold_t& fold = instance_of<fold_t>::instance; I usual hide the last line in a macro: INSTANCE_OF(fold_t, fold); Can EGG_CONST do something like this?
Anyway, I want to follow the Boost.Proto way.
boost::result_of<T_curry2(F const &)>::type c = curry2(f); // dynamic
or egg::return_of if you want recursive evaluation.
I'm not sure return_of is portable under msvc. That trivial example( http://tinyurl.com/yuumdv ) actually doesn't compile. :-(
Ah, ok. I also had problems with gcc.3.3 not digesting complex function type expressions. May be this syntax would be better: return_of<function_name, Arg1, Arg2, Arg3>::type and you can compose it like this: return_of<function1, return_of<function2, Arg1_1>, Arg2_1>::type This is more mpl friendly (result_of is a pain to use with mpl).
stateless_result_of<T_curry2(F)>::type c = BOOST_EGG_STATELESS(); // for stateless one.
Why not:
expression<T_curry2(F)> c = { /*just this please :) */ }; // note the missing ::type
It seems impossible to remove ::type, because `expression` can't use inheritance so that it can be a POD.
I do not think that podness is a problem, is just that it seems that the brace initializer can't be used with inheritance. But may be if the wrapped function object *really* stateless, you need no inheritance. You could just instantiate it directly in operator().
Well, 8.5.1 -14- states that "When an aggregate with static storage duration...". I think that if "an aggregate" means also "subaggregate", `{}` is not enough. Anyway, I should wait for Eric's answer.
yep.
BTW, expression<T_curry2(F)>::type c = {{}}; is feasible.
That would be very fine with me. But do you really need the double braces? -- gpd

On Thu, Apr 3, 2008 at 2:21 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Thu, Apr 3, 2008 at 1:53 AM, shunsuke <pstade.mb@gmail.com> wrote:
expression<T_curry2(F)>::type c = {{}}; is feasible.
That would be very fine with me. But do you really need the double braces?
Ah, now I see, you actually store the expression value in a field, and gcc complains if it is missing the second nested braces. -- gpd

Giovanni Piero Deretta wrote:
On Thu, Apr 3, 2008 at 1:53 AM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
You expect something like this?:
static_result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2({}); // static
Can't you use boost::result_of here? (or return_of)
As I mentioned, result_of needs to know whether or not an argument is lvalue or rvalue. result_of is standardized, so that I don't like to violate the law.
I still do not get it though. Could you show me exactly where you think the problem is?
boost::result_of<F(T)>::type
will return the type of the result of 'F()(T());' right? Once you know the type, and if you are sure that the type is an aggregate, doing 'boost::result_of<F(T)>::type c = {};' should always be legal. What I'm missing?
No. I'm just thinking twice about result_of without function-calls. For http://tinyurl.com/yuumdv, I have to admit such result_of, after all.
Also, as Eric stated in Proto doc, result_of compiles slow.
Ok. Is your static_result_of faster? And if so, couldn't you just port your improvements to the basic result_of? (or there are differences that allow you to take shortcuts?).
I think of specializing boost::result_of directly: template<class F> struct result_of<T_curry2(F)> : egg::result_of_curry2<typename remove_cv_ref<F>::type> { }; Though Eric states that even remove_cv_ref makes compiling slower, it's worth a try.
Also, do you have a plan for allowing complex statically initialized expressions in header files without ODR violations?
Though BOOST_EGG_CONST does nothing for now, it has the potential to work around the ODR violation. But I hesitate to say "Any function definition requires a macro!".
Only if you want to put them in an header file. Just to clarify, what I do is this:
template<typename Aggregate> struct instance_of { static Aggregate instance; };
template<typename Aggregate> Aggregate instance_of::instance = {};
Then I use it like this:
// in an header const fold_t& fold = instance_of<fold_t>::instance;
I usual hide the last line in a macro:
INSTANCE_OF(fold_t, fold);
Can EGG_CONST do something like this?
Yes. EGG_CONST was called POD_CONSTANT: http://tinyurl.com/2bdk5c The static_initialization is really tested by libs/test/static_initialization.cpp. One day, that test was failed around egg::indirect. POD_CONSTANT((int), v) = 0; // gcc can static-initialize v. msvc can't (without optimizer). POD_CONSTANT((int *), p) = &v; // Doh, gcc CAN'T static-initialize p. msvc can't of course. Thus, EGG_CONST has been turned into just `const`. I guess the ODR violation workaround will never be turned on.
Anyway, I want to follow the Boost.Proto way.
boost::result_of<T_curry2(F const &)>::type c = curry2(f); // dynamic
or egg::return_of if you want recursive evaluation.
I'm not sure return_of is portable under msvc. That trivial example( http://tinyurl.com/yuumdv ) actually doesn't compile. :-(
Ah, ok. I also had problems with gcc.3.3 not digesting complex function type expressions. May be this syntax would be better:
return_of<function_name, Arg1, Arg2, Arg3>::type
and you can compose it like this:
return_of<function1, return_of<function2, Arg1_1>, Arg2_1>::type
This is more mpl friendly (result_of is a pain to use with mpl).
Ok. I'm going to rewrite return_of.
stateless_result_of<T_curry2(F)>::type c = BOOST_EGG_STATELESS(); // for stateless one.
Why not:
expression<T_curry2(F)> c = { /*just this please :) */ }; // note the missing ::type
It seems impossible to remove ::type, because `expression` can't use inheritance so that it can be a POD.
I do not think that podness is a problem, is just that it seems that the brace initializer can't be used with inheritance. But may be if the wrapped function object *really* stateless, you need no inheritance. You could just instantiate it directly in operator().
Egg has the ForwardingStrategies. For example, the perfect forwarding must be implemented using egg::function<L, by_perfect>. Otherwise, yet another 2^N operator()s would be needed. Regards, -- Shunsuke Sogame

shunsuke wrote:
Though Eric states that even remove_cv_ref makes compiling slower, it's worth a try.
There is a context to that statement. Proto is used to build TMP-heavy libraries, and in normal operation causes recursive template instantiations -- lots of them. If I can save one template instantiation when calculating the return type of a transform, it's a big win because that savings get multiplied out and becomes measurable. That doesn't appear to be the case here, does it? Have you benchmarked compile times? -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
That doesn't appear to be the case here, does it? Have you benchmarked compile times?
Not yet. Anyway I probably find the best way. I'm making return_of be the main interface. result_of will be demoted to a customization point. Regards, -- Shunsuke Sogame

shunsuke wrote:
Eric Niebler wrote:
That doesn't appear to be the case here, does it? Have you benchmarked compile times?
Not yet. Anyway I probably find the best way. I'm making return_of be the main interface. result_of will be demoted to a customization point.
I confess I haven't followed this discussion closely or had time yet to review Egg, but this doesn't sound right to me. result_of shouldn't be a customization point. It uses a well-known (and now standard) protocol. And I don't know what return_of is for, but at best it's too easily confused with result_of and at worst is needless interface duplication. Can you explain what's going on here? -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
shunsuke wrote:
Eric Niebler wrote:
That doesn't appear to be the case here, does it? Have you benchmarked compile times? Not yet. Anyway I probably find the best way. I'm making return_of be the main interface. result_of will be demoted to a customization point.
I confess I haven't followed this discussion closely or had time yet to review Egg, but this doesn't sound right to me. result_of shouldn't be a customization point. It uses a well-known (and now standard) protocol. And I don't know what return_of is for, but at best it's too easily confused with result_of and at worst is needless interface duplication.
I also thought so, so that I removed return_of from Egg review version.
Can you explain what's going on here?
gpd's `compose` example is cool, so that I want something like this: return_of<T_uncurry(T_curry2(F))>::type c = ...; Anyway return_of is a syntax sugar around result_of. Is this a needless duplication? Regards, -- Shunsuke Sogame

Giovanni Piero Deretta wrote:
BTW, expression<T_curry2(F)>::type c = {{}}; is feasible.
That would be very fine with me. But do you really need the double braces?
Well, after you and Eric's suggestion, and some thoughts, I found that a newly introduced name can be `static_` only. How about this? : Adapting stateful functions with static-initialization: // already supported in review version result_of<T_curry2(F)>::type c = BOOST_EGG_CURRY2(&f); Adapting runtime functions: // already supported, of course. result_of<T_curry2(F const &)>::type c = curry2(f); Adapting stateless functions with static-initialization: // the newly proposed feature (macros unneeded.) static_< result_of<T_curry2(F)> >::type c = {{}}; // BTW, this feature can be translated into the current review version: // static_< mpl::always<result_of<T_curry2(F)>::type> >::type c = BOOST_EGG_STATIC(); // static_ is generic enough: static_< std::plus<int> >::type p = {{}}; The document will put much greater empahsis on the new feature than the macro features, and it will be very simplified. // Also, I've added the secret support for return_of ;-) // See: http://tinyurl.com/32dbq8 // After good experiences, (or if a portable workaround for round lambda syntax is found,) // this may be officially added. BTW, I'm making all the braced-initializers of Function Builders be `{{}}` so that those macros will be removed. `{{}}` seems not so bad, because it is the same as egg::function<>'s. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 1:59 AM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
BTW, Boost.Egg has the potential to implement your compose.
typedef result_of_lazy<fold>::type fold_; typedef result_of_lazy<reverse>::type reverse_; typedef return_of<fold_(reverse_(T_bll_1), T_bll_2, T_bll_3)>::type reverse_fold;
Oh! So Egg has the functionality to make function objects directly usable in lambda expressions (without bind)??? i.e.
for_each(range_of_ranges, regular(protect(std::cout << accumulate(ll::_1, 0))))
does that actually work? (for appropriate definitions of for_each and accumulate, of course). I was going to ask you to provide this functionality in egg (yes, I'm working on a review :) )
Yes. egg::lazy/nestN makes bind/protect deprecated. I've noticed that bind/protect is a customization point. e.g.
X_lazy<T_boost_bind> bb_lazy; // T_boost_bind represents boost::bind. bb_lazy(foo)(::_1, 2);
In fact, implementing T_boost_bind is so difficult that Egg skips it. :-)
BTW, i prefer to spell 'regular(protect(...))' as 'lambda[...]'
What is `regular`? Is it the same as egg::regular?
yes, exactly. I do not have a 'regular' function, I've just used this name because this is what egg uses.
BTW, everything must be function-call to support result_of.
What do you mean exactly with "everything must be function call?".
Even if I guarantee that my function objects (in this case fold and reverse) are stateless? Does using the lambda placeholders complicate things?
If fold_ is DefaultConstructible and a default-constructed one is callable, it would be:
typedef static_< mpl::always< return_of<T_regular(fold_(reverse_(T_bll_1), T_bll_2, T_bll_3))>::type > > reverse_fold;
I tend to hesitate to use result_of/return_of without function-calls.
Again, what do you mean exactly? And why do you esistate? I'm evaluating egg design, so these answers would be very valuable.
So your `compose` may be a candidate of yet another lambda framework.
As if there weren't already enough :) -- gpd

Giovanni Piero Deretta wrote:
BTW, everything must be function-call to support result_of.
What do you mean exactly with "everything must be function call?".
result_of<T_lambda(T1)>::type r = lambda(t1); // ok, result_of compatible. ??? r = lambda[t1]; Yet another trait(something like result_of_bracket_op) would be needed. I don't like it.
I tend to hesitate to use result_of/return_of without function-calls.
Again, what do you mean exactly? And why do you esistate? I'm evaluating egg design, so these answers would be very valuable.
E.g. result_of<F(T1)>::type s; result_of is a trait which extracts return type of function-calls, but s is default-constructed without function-calls. Regards, -- Shunsuke Sogame

On Wed, Apr 2, 2008 at 6:01 PM, shunsuke <pstade.mb@gmail.com> wrote:
Giovanni Piero Deretta wrote:
BTW, everything must be function-call to support result_of.
What do you mean exactly with "everything must be function call?".
result_of<T_lambda(T1)>::type r = lambda(t1); // ok, result_of compatible.
This wouldn't compile in my model, you can't call 'lambda' using operator() (well, I plan to support scoped variables a-la phoenix one day, but for the moment it simply doens't compile).
??? r = lambda[t1];
result_of<T_lambda(T1)>::type r = lambda[t1] might work just fine, but maybe overloading result_of is not nice. What about: protected<t1> r = lambda[t1]
[...]
I tend to hesitate to use result_of/return_of without function-calls.
Again, what do you mean exactly? And why do you esistate? I'm evaluating egg design, so these answers would be very valuable.
E.g. result_of<F(T1)>::type s;
result_of is a trait which extracts return type of function-calls, but s is default-constructed without function-calls.
Well, what is the problem? As long as there is no bind-like function in there which requires passing closure parameters, it should be fine. I agree that it might be confusing initially. -- gpd

Giovanni Piero Deretta wrote:
??? r = lambda[t1];
result_of<T_lambda(T1)>::type r = lambda[t1]
might work just fine, but maybe overloading result_of is not nice. What about:
protected<t1> r = lambda[t1]
I like making everything be FunctionObject so that result_of can be used everywhere. Anyway, this depends on rationale of a library.
[...]
I tend to hesitate to use result_of/return_of without function-calls.
Again, what do you mean exactly? And why do you esistate? I'm evaluating egg design, so these answers would be very valuable.
E.g. result_of<F(T1)>::type s;
result_of is a trait which extracts return type of function-calls, but s is default-constructed without function-calls.
Well, what is the problem? As long as there is no bind-like function in there which requires passing closure parameters, it should be fine. I agree that it might be confusing initially.
Strictly speaking, when you don't know whether an argument is a lvalue or rvalue, result_of cannot be used. In other words, runtime object as argument is needed. So, I think yet another name ("imaginary_result_of" or something) is needed. Regards, -- Shunsuke Sogame
participants (5)
-
David Abrahams
-
Eric Niebler
-
Giovanni Piero Deretta
-
shunsuke
-
Steven Watanabe