Re: [boost] I'd like to write a static lambda library.

I couldn't find out quickly if you're applying BOOST_TYPEOF to passed lambda expression but if you do, it would blow up your computer if compiler doesn't support native typeof (Hint: try passing -DBOOST_TYPEOF_COMPLIANT to compiler's arguments). Have you considered something like int (*static_fun)(int const&, int const&) = (_1 + _2 + 3).get_static_function(1, 2); get_static_function does not necessarily accept values, it may have a different interface: (_1 + _2 + 3).get_static_function<int const&, int const&>(); (_1 + _2 + 3).get_static_function(mpl::vector<int const&, int const&>()); Does your idea help to improve performance and/or reduce size of program that has a lot of conversions from lambda expressions to tr1::function? 26.06.07, 17:31, Atry <pop.atry@gmail.com>:
I wrote a intial version, I have tested it on cygwin ported gcc 3.4.4 and msvc 7.1, for more infomation, see README and tests in zip packet in vault. http://boost-consulting.com/vault/index.php?direction=0&order=&directory=Generic%20Programming On 6/25/07, Atry <pop.atry@gmail.com> wrote:
-- Alexander Nasonov

Alexander Nasonov wrote:
I couldn't find out quickly if you're applying BOOST_TYPEOF to passed lambda expression but if you do, it would blow up your computer if compiler doesn't support native typeof (Hint: try passing -DBOOST_TYPEOF_COMPLIANT to compiler's arguments).
Have you considered something like
int (*static_fun)(int const&, int const&) = (_1 + _2 + 3).get_static_function(1, 2);
get_static_function does not necessarily accept values, it may have a different interface: (_1 + _2 + 3).get_static_function<int const&, int const&>(); (_1 + _2 + 3).get_static_function(mpl::vector<int const&, int const&>());
Does your idea help to improve performance and/or reduce size of program that has a lot of conversions from lambda expressions to tr1::function?
26.06.07, 17:31, Atry <pop.atry@gmail.com>:
I wrote a intial version, I have tested it on cygwin ported gcc 3.4.4 and msvc 7.1, for more infomation, see README and tests in zip packet in vault. http://boost-consulting.com/vault/index.php?direction=0&order=&directory=Generic%20Programming On 6/25/07, Atry <pop.atry@gmail.com> wrote:
Yes, getting a static function pointer is easy, I will add that method later. But I have highly depended on typeof, I use typeof to determine the result of almost all expressions, and Boost.Lambda does not. Typeof enhanced lots of flexibility. For example, if a operator is overrided to return a unusual return value, for Boost.Lambda, you have to manually specify that return value using a "ret<return_type>(expr)" syntax. And I used typeof to avoid that. There is two situation need static lambda. a. To generate a short c function pointer. b. To generate a short generic function, and pass it to a template class. For example, I have some "component" class, and each of them depend on some others. How could they find each other? one way is pass a pointer. /* code begin */ class component_a { public: void foo(); }; class component_b { private: component_a* a_; public: component_b(component_a* a) : a_(a) {} void bar() { foo(); } }; class global_object { public: component_a a_; component_b b_; global_object() : a_(), b_(&a_) { b_.bar(); } }; int main() { global_object g; } /* code end */ As you see, there is a component_a and a component_b. Component_b depends on component_a, and global_object combine these two. But it is not flexible enough. Firstly, component_b used a fixed type of component_a, we can't have another implement of component_a. Secondly, the pointer to component_a in component_b is unwanted, there is some way to avoid that pointer. Look at the improved version using static lambda: /* code begin */ #include <boost/assert.hpp> #include <boost/static_lambda.hpp> #include <cstddef> class component_a { public: int foo() { return 1; } }; template<typename Locator_A> class component_b { public: void bar() { BOOST_ASSERT(Locator_A::static_invoke(this)->foo() == 1); } }; struct locator_to_a; class global_object { public: component_a a_; component_b<locator_to_a> b_; global_object() : a_(), b_() { b_.bar(); } }; // declare constant "offset_of_a". BOOST_STATIC_LAMBDA_AUTO_EXPRESSION(offset_of_a, offsetof(global_object, a_)); // declare constant "offset_of_b". BOOST_STATIC_LAMBDA_AUTO_EXPRESSION(offset_of_b, offsetof(global_object, b_)); using namespace boost::static_lambda; // the static lambda function. note: constructing a pointer equals to casting to a pointer. typedef BOOST_STATIC_LAMBDA_FUNCTOR ( construct<component_a*> ( construct<char*>(_1) - offset_of_b + offset_of_a ) ) l; struct locator_to_a : l{}; int main() { global_object g; } /* code end */

Atry wrote:
Alexander Nasonov wrote: Yes, getting a static function pointer is easy, I will add that method later. But I have highly depended on typeof, I use typeof to determine the result of almost all expressions, and Boost.Lambda does not. Typeof enhanced lots of flexibility. For example, if a operator is overrided to return a unusual return value, for Boost.Lambda, you have to manually specify that return value using a "ret<return_type>(expr)" syntax. And I used typeof to avoid that.
I agree that typeof is a very powerful tool but it's still non-standard. Would it work if you enhance Boost.Lambda without using non-standard extensions and then apply BOOST_TYPEOF in your _client_ code? -- Alexander Nasonov http://nasonov.blogspot.com Error of opinion may be tolerated where reason is left free to combat it. -- Thomas Jefferson -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

It can not work now. But I will make expressions like BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2) always worked for both native or emulated typeof this week. Unfortunately, BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2 * _1)::static_invoke(custom_value1, custom_value2) will never work if result of custom_value2*custom_value1 or custom_value1+custom_value2*custom_value1 is a unregistered type for the platform does not have native typeof. The client not have native typeof have to register all type may be evaluated is registered. On 6/27/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Atry wrote:
Alexander Nasonov wrote: Yes, getting a static function pointer is easy, I will add that method later. But I have highly depended on typeof, I use typeof to determine the result of almost all expressions, and Boost.Lambda does not. Typeof enhanced lots of flexibility. For example, if a operator is overrided to return a unusual return value, for Boost.Lambda, you have to manually specify that return value using a "ret<return_type>(expr)" syntax. And I used typeof to avoid that.
I agree that typeof is a very powerful tool but it's still non-standard. Would it work if you enhance Boost.Lambda without using non-standard extensions and then apply BOOST_TYPEOF in your _client_ code?
-- Alexander Nasonov http://nasonov.blogspot.com
Error of opinion may be tolerated where reason is left free to combat it. -- Thomas Jefferson --
This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

I will reimplement all code. So it would not be done this week. Atry wrote:
It can not work now. But I will make expressions like BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2) always worked for both native or emulated typeof this week. Unfortunately, BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2 * _1)::static_invoke(custom_value1, custom_value2) will never work if result of custom_value2*custom_value1 or custom_value1+custom_value2*custom_value1 is a unregistered type for the platform does not have native typeof. The client not have native typeof have to register all type may be evaluated is registered.
On 6/27/07, *Alexander Nasonov* <alnsn@yandex.ru <mailto:alnsn@yandex.ru>> wrote:
Atry wrote: > Alexander Nasonov wrote: > Yes, getting a static function pointer is easy, I will add that method > later. But I have highly depended on typeof, I use typeof to determine > the result of almost all expressions, and Boost.Lambda does not. Typeof > enhanced lots of flexibility. For example, if a operator is overrided to > return a unusual return value, for Boost.Lambda, you have to manually > specify that return value using a "ret<return_type>(expr)" syntax. And I > used typeof to avoid that.
I agree that typeof is a very powerful tool but it's still non-standard. Would it work if you enhance Boost.Lambda without using non-standard extensions and then apply BOOST_TYPEOF in your _client_ code?
-- Alexander Nasonov http://nasonov.blogspot.com
Error of opinion may be tolerated where reason is left free to combat it. -- Thomas Jefferson --
This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost <http://lists.boost.org/mailman/listinfo.cgi/boost>

Atry wrote:
It can not work now. But I will make expressions like BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2) always worked for both native or emulated typeof this week.
Atry, I started replying immediately but I realised that I should take a closer look at your code. Unfortunately, I didn't have time. So, I started with: Is it possible to get rid of the BOOST_STATIC_LAMBDA_FUNCTOR macro completely? I'm thinking of this interface: // Return an object of unspecified type F such that // F::invoke(arg1, ...) [static] - equivalent to invocation of expr(arg1, ...) // F::get_static_function<Sig>() [static] - return an address of // F::invoke<Arg1, ...> where Sig is a function type R(Arg1, ...). template<class Expr> typename resultof_make_static_functor<Expr>::type make_static_functor(Expr); template<class Sig, class Expr> Sig* make_static_function(Expr) { return make_static_functor(expr)::get_static_function<Sig>(); } Some examples: make_static_functor(_1 + _2)::invoke(1, 2); typedef BOOST_TYPEOF( make_static_functor(_1 + _2) ) my_static_lambda; // ( assuming you support stateful lambdas ) int (*inc)(int const&) = make_static_function<int(int const&)>(_1 + 1);
Unfortunately, BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2 * _1)::static_invoke(custom_value1, custom_value2) will never work if result of custom_value2*custom_value1 or custom_value1+custom_value2*custom_value1 is a unregistered type for the platform does not have native typeof. The client not have native typeof have to register all type may be evaluated is registered.
I stopped here because I couldn't make a good comment without understanding BOOST_STATIC_LAMBDA_FUNCTOR internals. Now, rather than commenting your statements I'd like to add a more general comment. In your previous post you wrote "I use typeof to determine the result of almost all expressions, and Boost.Lambda does not". Unfortunately, it's not always possible to add cool things to a library because it should support broken compilers, it should not break existing code (a need to register every type in emulation mode is a breaking change) and so on. Your change should be consistent with a rest of library. Typeof stuff can wait. I'm sure there will be an interest in this change for the whole library, not only for your small addition. -- Alexander Nasonov - http://nasonov.blogspot.com A friend is the hope of the heart. -- Ralph Waldo Emerson -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt

Yes, if you see static_lambda.hpp, you will find this: #define BOOST_STATIC_LAMBDA_FUNCTOR(expr) BOOST_TYPEOF(to_functor(expr)) And this is to_functor: template<typename Tag> static functor<Tag> to_functor(expression<Tag>) { return functor<Tag>(); } As you see, functor<> is a helper for user to invoke functions, and expression<> is a helper overloading operators to generate expressions. On 6/29/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Atry wrote:
It can not work now. But I will make expressions like BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2) always worked for both native or emulated typeof this week.
Atry, I started replying immediately but I realised that I should take a closer look at your code. Unfortunately, I didn't have time.
So, I started with:
Is it possible to get rid of the BOOST_STATIC_LAMBDA_FUNCTOR macro completely? I'm thinking of this interface:
// Return an object of unspecified type F such that // F::invoke(arg1, ...) [static] - equivalent to invocation of expr(arg1, ...) // F::get_static_function<Sig>() [static] - return an address of // F::invoke<Arg1, ...> where Sig is a function type R(Arg1, ...). template<class Expr> typename resultof_make_static_functor<Expr>::type make_static_functor(Expr);
template<class Sig, class Expr> Sig* make_static_function(Expr) { return make_static_functor(expr)::get_static_function<Sig>(); }
Some examples:
make_static_functor(_1 + _2)::invoke(1, 2);
typedef BOOST_TYPEOF( make_static_functor(_1 + _2) ) my_static_lambda;
// ( assuming you support stateful lambdas ) int (*inc)(int const&) = make_static_function<int(int const&)>(_1 + 1);
Unfortunately, BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2 * _1)::static_invoke(custom_value1, custom_value2) will never work if result of custom_value2*custom_value1 or custom_value1+custom_value2*custom_value1 is a unregistered type for the platform does not have native typeof. The client not have native typeof have to register all type may be evaluated is registered.
I stopped here because I couldn't make a good comment without understanding BOOST_STATIC_LAMBDA_FUNCTOR internals.
Now, rather than commenting your statements I'd like to add a more general comment. In your previous post you wrote "I use typeof to determine the result of almost all expressions, and Boost.Lambda does not". Unfortunately, it's not always possible to add cool things to a library because it should support broken compilers, it should not break existing code (a need to register every type in emulation mode is a breaking change) and so on. Your change should be consistent with a rest of library. Typeof stuff can wait. I'm sure there will be an interest in this change for the whole library, not only for your small addition. -- Alexander Nasonov - http://nasonov.blogspot.com
A friend is the hope of the heart. -- Ralph Waldo Emerson -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

I will reimplement static_lambda, and remove all typeof. The other reason I have to reimplement is macros. I used too many BOOST_PP_ENUM and BOOST_PP_REPEAT for different number of parameter on function calling, constructing and local variant initializing. That makes my code too bad. I intend to use fusion to avoid these BOOST_PP_ENUM and BOOST_PP_REPEAT.On 6/29/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
In your previous post you wrote "I use typeof to determine the result of almost all expressions, and Boost.Lambda does not". Unfortunately, it's not always possible to add cool things to a library because it should support broken compilers, it should not break existing code (a need to register every type in emulation mode is a breaking change) and so on. Your change should be consistent with a rest of library. Typeof stuff can wait. I'm sure there will be an interest in this change for the whole library, not only for your small addition. -- Alexander Nasonov - http://nasonov.blogspot.com
A friend is the hope of the heart. -- Ralph Waldo Emerson -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

The functions generated by static lambda will be very similar to C functions. It would not bind any data. Runtime cost of static lambda expression is zero. On 6/26/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
I couldn't find out quickly if you're applying BOOST_TYPEOF to passed lambda expression but if you do, it would blow up your computer if compiler doesn't support native typeof (Hint: try passing -DBOOST_TYPEOF_COMPLIANT to compiler's arguments).
Have you considered something like
int (*static_fun)(int const&, int const&) = (_1 + _2 + 3).get_static_function(1, 2);
get_static_function does not necessarily accept values, it may have a different interface: (_1 + _2 + 3).get_static_function<int const&, int const&>(); (_1 + _2 + 3).get_static_function(mpl::vector<int const&, int const&>());
Does your idea help to improve performance and/or reduce size of program that has a lot of conversions from lambda expressions to tr1::function?
26.06.07, 17:31, Atry <pop.atry@gmail.com>:
I wrote a intial version, I have tested it on cygwin ported gcc 3.4.4and msvc 7.1, for more infomation, see README and tests in zip packet in vault.
http://boost-consulting.com/vault/index.php?direction=0&order=&directory=Generic%20Programming
On 6/25/07, Atry <pop.atry@gmail.com> wrote:
-- Alexander Nasonov _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Atry wrote:
The functions generated by static lambda will be very similar to C functions. It would not bind any data. Runtime cost of static lambda expression is zero.
extern "C" lambda staff ;) Does it use local static variable to hold a state of stateful lambda objects? This fact should be documented. -- Alexander Nasonov http://nasonov.blogspot.com The most incomprehensible thing about the world is that it is at all comprehensible. -- Albert Einstein -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

On 6/28/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Atry wrote:
The functions generated by static lambda will be very similar to C functions. It would not bind any data. Runtime cost of static lambda expression is zero.
extern "C" lambda staff ;)
Does it use local static variable to hold a state of stateful lambda objects? This fact should be documented.
I took a brief look at this. As far as I could tell Atry's library is stateless. So, it can only support a subset of the expressions that Boost.Lambda supports... namely those without state; i.e. all the parameters need to be unbound. So, it can do _1 << _2 << _3 ... but not ... cout << _1 << endl I'm not sure that this wins you a time savings over Boost.Lambda, but I believe it could win you a space saving if the static function can be inlined. I wonder how this relates to the anticipated rewrite of lambda using Phoenix. Daniel

Daniel Walker wrote:
I took a brief look at this. As far as I could tell Atry's library is stateless. So, it can only support a subset of the expressions that Boost.Lambda supports... namely those without state; i.e. all the parameters need to be unbound. So, it can do
_1 << _2 << _3
... but not ...
cout << _1 << endl
I'm not sure that this wins you a time savings over Boost.Lambda,
If stateful lambda object isn't small enough to fit into boost::function buffer, it could save you one dynamic memory allocation for each object.
but I believe it could win you a space saving if the static function can be inlined. Or quite the opposite. Though, I hope people don't write big scary lambdas expressions.
I wonder how this relates to the anticipated rewrite of lambda using Phoenix. me either.
-- Alexander Nasonov - http://nasonov.blogspot.com How we spend our days is, of course, how we spend our lives. -- Annie Dillard -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt

On 6/28/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Daniel Walker wrote:
I took a brief look at this. As far as I could tell Atry's library is stateless. So, it can only support a subset of the expressions that Boost.Lambda supports... namely those without state; i.e. all the parameters need to be unbound. So, it can do
_1 << _2 << _3
... but not ...
cout << _1 << endl
I'm not sure that this wins you a time savings over Boost.Lambda,
If stateful lambda object isn't small enough to fit into boost::function buffer, it could save you one dynamic memory allocation for each object.
True, but I don't think this handles stateful expressions, so the opportunity never comes up. Actually, you can't bind an object through typeof to a type. That's dizzying to think about. You could do some initialization in the macro after you deduce the type, but then there are going to be trade-offs... static variables or not supporting in one macro both typedef BOOST_STATIC_LAMBDA_FUNCTOR(_1 << _2 << _3) left_shift_type; and BOOST_STATIC_LAMBDA_FUNCTOR(_1 + _2 * _3)::invoke(1, 3, 5)
but I believe it could win you a space saving if the static function can be inlined. Or quite the opposite. Though, I hope people don't write big scary lambdas expressions.
Right. Actually, now that I think about it I'm getting a little confused about scenarios where this could save you space. I think they may be limited.

Daniel Walker wrote:
Right. Actually, now that I think about it I'm getting a little confused about scenarios where this could save you space. I think they may be limited.
Scenarios for static stateless lambda expressions are limited, so it's not a surprise that scenarios where this could save you space are limited too ;) We should carefully think about static _stateful_ lambda expressions. Some lambda expressions contain only constants and these expressions can be "complied" into static function. Though, it may lead to a confusion when a user pass a variable (not constant!) but static lambda uses a value passed first time. int x = 0; (_1 + x).get_static_function<int>()(0); // returns 0 - ok x = 1; (_1 + x).get_static_function<int>()(0); // returns 0 - bad Too bad. I have another use-case where stateful lambda could be useful but above problem doesn't give it any real chance :-( -- Alexander Nasonov - http://nasonov.blogspot.com Pennies do not come from heaven. They have to be earned here on earth. -- Margaret Thatcher -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt

There is an sample for static_lambda use of static variant: /* begin */ int a = 5; int sub(int l, int r) { return l - r; } BOOST_STATIC_LAMBDA_DECLARE_EXPRESSION(int, expr_a, a); // equals to BOOST_STATIC_LAMBDA_DECLARE_EXPRESSION(BOOST_TYPEOF(&sub), expr_sub, &sub) BOOST_STATIC_LAMBDA_AUTO_EXPRESSION(expr_sub, &sub); int main() { BOOST_ASSERT(to_functor(expr_sub(constant<boost::mpl::int_<62> >(), expr_a)).static_invoke() == sub(62, a)); a = 10; BOOST_ASSERT(to_functor(expr_sub(constant<boost::mpl::int_<62> >(), expr_a))() == sub(62, a)); } /* end */ Any static variant be used must register first, because I can't get a variant value in compile time. Another way is using constant<>, like constant<boost::mpl::int_<62> >(). On 6/29/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Daniel Walker wrote:
Right. Actually, now that I think about it I'm getting a little confused about scenarios where this could save you space. I think they may be limited.
Scenarios for static stateless lambda expressions are limited, so it's not a surprise that scenarios where this could save you space are limited too ;)
We should carefully think about static _stateful_ lambda expressions. Some lambda expressions contain only constants and these expressions can be "complied" into static function. Though, it may lead to a confusion when a user pass a variable (not constant!) but static lambda uses a value passed first time.
int x = 0; (_1 + x).get_static_function<int>()(0); // returns 0 - ok x = 1; (_1 + x).get_static_function<int>()(0); // returns 0 - bad
Too bad. I have another use-case where stateful lambda could be useful but above problem doesn't give it any real chance :-(
-- Alexander Nasonov - http://nasonov.blogspot.com
Pennies do not come from heaven. They have to be earned here on earth. -- Margaret Thatcher -- /---------------------------- Fortune script ----------------------------\ curl 'http://www.quotedb.com/quote/quote.php?action=random_quote&=&=&' | \ sed -e "s/^[^']*'//;s/.);$/ --/;s/<[^>]*>//g;2s/^.\{17\}//" | fmt _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (3)
-
Alexander Nasonov
-
Atry
-
Daniel Walker