
Hello. This won't be a proper review of the library, but more a point of view of an average Boost user. ScopeExit seems like a very nice utility, but, I don't think I could ever use it because of two things: 1. Dependence on boost.typeof. I would like the native typeof keyword, but, boost.typeof too much stresses compile type and a requirement of type registration is so unergonomic that makes boost.typeof a very nice and powerful demo, but not a useful utility for every day use. 2. Unusual syntax, both for me and someone who would later work on my code. Using preprocessor sequence and having BOOST_SCOPE_EXIT_END after {} braces looks so unnatural in C++. If, by any chance, my vote will be counted, I'll vote no for this utility until those two items are resolved. I understand maybe it's not possible to do so, but, I would rather not have it in Boost then.

2007/8/20, Goran Mitrovic <gmit@inet.hr>:
Hello.
This won't be a proper review of the library, but more a point of view of an average Boost user.
ScopeExit seems like a very nice utility, but, I don't think I could ever use it because of two things:
1. Dependence on boost.typeof. I would like the native typeof keyword, but, boost.typeof too much stresses compile type and a requirement of type registration is so unergonomic that makes boost.typeof a very nice and powerful demo, but not a useful utility for every day use.
BOOST_TYPEOF reverts to native typeof on all compilers that support it. In addition, BOOST_TYPEOF is supported 'natively' on all VC compilers (ranging from VC6.0 to VC8.0), by utilizing a bug in the compiler. No registration is needed if you only target these platforms, and the compile time overhead on these compilers is negligible. Regards, Peder
2. Unusual syntax, both for me and someone who would later work on my code. Using preprocessor sequence and having BOOST_SCOPE_EXIT_END after {} braces looks so unnatural in C++.
If, by any chance, my vote will be counted, I'll vote no for this utility until those two items are resolved. I understand maybe it's not possible to do so, but, I would rather not have it in Boost then.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

BOOST_TYPEOF reverts to native typeof on all compilers that support it. In addition, BOOST_TYPEOF is supported 'natively' on all VC compilers (ranging from VC6.0 to VC8.0), by utilizing a bug in the compiler. No registration is needed if you only target these platforms, and the compile time overhead on these compilers is negligible.
It's my understanding that as of MSVC8.0 the MS compiler no longer contains the bug used to implement typeof, so we don't get native typeof. I'm unsure about the status of the bug or native typeof in the next Visual Studio (Orcas?). There may be considerable scope for improving this library if native typeof and variadic macros make it into C++0x.

2007/8/20, Joseph Gauterin <joseph.gauterin@googlemail.com>:
BOOST_TYPEOF reverts to native typeof on all compilers that support it. In addition, BOOST_TYPEOF is supported 'natively' on all VC compilers (ranging from VC6.0 to VC8.0), by utilizing a bug in the compiler. No registration is needed if you only target these platforms, and the compile time overhead on these compilers is negligible.
It's my understanding that as of MSVC8.0 the MS compiler no longer contains the bug used to implement typeof, so we don't get native typeof. I'm unsure about the status of the bug or native typeof in the next Visual Studio (Orcas?).
This is true for the official release, but not for the development branch. Steven Watanabe submitted a patch for BOOST_TYPEOF where he utilises a similar bug for VC8.0, enabling 'native' typeof for this compiler as well. Regards Peder
There may be considerable scope for improving this library if native typeof and variadic macros make it into C++0x. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Goran Mitrovic <gmit <at> inet.hr> writes:
ScopeExit seems like a very nice utility, but, I don't think I could ever use it because of two things:
1. Dependence on boost.typeof. I would like the native typeof keyword, but, boost.typeof too much stresses compile type and a requirement of type registration is so unergonomic that makes boost.typeof a very nice and powerful demo, but not a useful utility for every day use.
AFAIK, native mode is default if compiler supports typeof/decltype. So you can skip type registration if your compiler supports typeof natively.
2. Unusual syntax, both for me and someone who would later work on my code. Using preprocessor sequence and having BOOST_SCOPE_EXIT_END after {} braces looks so unnatural in C++.
Have you tried boost.lambda? I bet you will feel comfortable with ScopeExit syntax after writing 10 ScopeExit bodies but mastering lambda skills would take a month. I spent 5 minutes writing and debugging lambda for Alternatives.ScopeGuard section but it took me only 10 seconds to type ScopeExit. -- Alexander

on Mon Aug 20 2007, Alexander Nasonov <alnsn-AT-yandex.ru> wrote:
2. Unusual syntax, both for me and someone who would later work on my code. Using preprocessor sequence and having BOOST_SCOPE_EXIT_END after {} braces looks so unnatural in C++.
Have you tried boost.lambda? I bet you will feel comfortable with ScopeExit syntax after writing 10 ScopeExit bodies but mastering lambda skills would take a month. I spent 5 minutes writing and debugging lambda for Alternatives.ScopeGuard section but it took me only 10 seconds to type ScopeExit.
I haven't often found myself in need of something like ScopeGuard/ScopeExit, but I am convinced that some people find it indispensible. I encourage those people to give the macros a chance, because what Alexander says about writing lambda expressions definitely rings true. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

On 8/20/07, David Abrahams <dave@boost-consulting.com> wrote:
on Mon Aug 20 2007, Alexander Nasonov <alnsn-AT-yandex.ru> wrote:
2. Unusual syntax, both for me and someone who would later work on my code. Using preprocessor sequence and having BOOST_SCOPE_EXIT_END after {} braces looks so unnatural in C++.
Have you tried boost.lambda? I bet you will feel comfortable with ScopeExit syntax after writing 10 ScopeExit bodies but mastering lambda skills would take a month. I spent 5 minutes writing and debugging lambda for Alternatives.ScopeGuard section but it took me only 10 seconds to type ScopeExit.
I haven't often found myself in need of something like ScopeGuard/ScopeExit, but I am convinced that some people find it indispensible. I encourage those people to give the macros a chance, because what Alexander says about writing lambda expressions definitely rings true.
I use boost lambda expression extensively, and I have a love/hate relationship with them. When you finally get a (complex) lambda to compile it might even be elegant and even readable, but getting there requires an inordinate amount of time. I do not have time right now for a review (I will try late this evening), but I think that the "inline" lambda capabilities of ScopeExit and its ScopeGuard-like functionality should be decoupled. The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda. Anyone would find such a mechanism useful? Alexander, do you think that it would be hard to extend ScopeExit to a generalized closure? I have done some experiments in the past with something like that and it seemed doable. gpd

Hello,
I haven't often found myself in need of something like ScopeGuard/ScopeExit, but I am convinced that some people find it indispensible. I encourage those people to give the macros a chance, because what Alexander says about writing lambda expressions definitely rings true.
I really like the way of writing the guard body using the scheme of ScopeExit, it seems to make it much easier to maintain compared to writing horrible lambda expressions or specialized function objects. What I'm missing is a way of nesting guards, making it possible to build complex transactions out of many small ones. The examples have very simple transactions that fit easily into a couple of lines, but this is not the case with what I am used to work with. Let's take the example from the docs: void World::addPerson(Person const& person) { bool commit = false; m_persons.push_back(person); BOOST_SCOPE_EXIT( (commit)(m_persons) ) { if(!commit) m_persons.pop_back(); } BOOST_SCOPE_EXIT_END // ... other operations commit = true; } Let's say I have two Worlds, and would like to add one person into each of these.I would prefer to write that like: boost::scope_guard guard; World world1, world2; world1.addPerson(guard, Person(...)); world2.addPersion(guard, Person(...)); guard.commit(); With the current proposal I don't see how I this could be done, since there is no visible notion of a context keeping the guards. For my own work i've written a simple scope_guard that holds a std::vector<boost::function>, where I add all lambda expressions to be invoked unless I call scope_guard::commit(). This works but the lambda mess remains. Would it be possible to maybe add such functionality on-top of the ScopeExit as it looks today? Best regards, Christian

AMDG Christian Holmquist <c.holmquist <at> gmail.com> writes:
Let's say I have two Worlds, and would like to add one person into each of these.I would prefer to write that like:
boost::scope_guard guard; World world1, world2;
world1.addPerson(guard, Person(...)); world2.addPersion(guard, Person(...));
guard.commit();
With the current proposal I don't see how I this could be done, since there is no visible notion of a context keeping the guards.
For my own work i've written a simple scope_guard that holds a std::vector<boost::function>, where I add all lambda expressions to be invoked unless I call scope_guard::commit(). This works but the lambda mess remains.
That isn't exception safe because 1) push_back can throw 2) function::function can throw You can think of the bool commit as the context keeping the guards. Unless you set it all the ScopeExit rollback actions will be executed exactly as in your example. In Christ, Steven Watanabe

Steven Watanabe wrote:
2) function::function can throw
I don't know how boost::function is implemented, but it should be possible that it can only throw if the function object contains state. And I think that should seldom happen. If it doesn't contain state, it should be possible to fallback to a two-pointer representation, where function owns nothing (and thus doesn't need to allocate memory) and only references code and context. (that is to say, std::nested_function from the lambda proposal)

On 8/21/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Steven Watanabe wrote:
2) function::function can throw
I don't know how boost::function is implemented, but it should be possible that it can only throw if the function object contains state. And I think that should seldom happen.
If it doesn't contain state, it should be possible to fallback to a two-pointer representation, where function owns nothing (and thus doesn't need to allocate memory) and only references code and context. (that is to say, std::nested_function from the lambda proposal)
IIRC the lastest verison of boost::function does exactly that. It uses a small object optimization for simple functors (like stateless ones and ptr to member function bound to a 'this' ptr). I do not think it actually *guarantees* that it will never do dynamic allocations, only that it will do its best, so probably you can't rely on it. How big is the small object buffer is probably implementation (and architecture) dependent. HTH, gpd

Giovanni Piero Deretta wrote:
IIRC the lastest verison of boost::function does exactly that. It uses a small object optimization for simple functors (like stateless ones and ptr to member function bound to a 'this' ptr). I do not think it actually *guarantees* that it will never do dynamic allocations, only that it will do its best, so probably you can't rely on it. How big is the small object buffer is probably implementation (and architecture) dependent.
That's good, however there is still something that could be improved by the function objects generators like boost.lambda. Take this for example: int main() { int a = 12; int b = 68; do_something(_1 + a + b); } Technically, this could probably generate something along the likes of: struct functor { int&& a; int&& b; functor(int&& a_, int&& b_) : a(a_), b(b_) { } template<typename T> decltype(std::make<T>() + a + b) operator()(T&& t) const { return t + a + b; } }; (imagining we had rvalues, decltype and std::make) However, the size of that object is linearily dependent on the number of variables we reference, and thus we might easily go over the small object optimization. I don't know how boost.lambda actually does it, but on my x86 box, sizeof(_1 + a + b) yields 12, which means there is an overhead of one word for some reason. We are rather sure to have it well optimized if we do this though: struct context { int&& a; int&& b; context(int&& a_, int&& b_) : a(a_), b(b_) { } }; int main() { int a = 12; int b = 68; context cxt(a, b); // ideally we could maybe even have the context directly owning the variables a and b, but that may be difficult to codegen with just templates and macros do_something(functor2(cxt)); } struct functor2 { context&& cxt; functor(context&& cxt_) : cxt(cxt_) { } template<typename T> decltype(std::make<T>() + cxt.a + cxt.b) operator()(T&& t) const { return t + cxt.a + cxt.b; } }; Here, whatever the number of variables we reference may be, our functor is always of the size of one word, meaning only two words are needed for it in boost::function : one for the code/type identification, another for the context. (plus probably a boolean that says whether we need to delete or not) It would be nice if we had a lambda engine that could automatically do such magic. This would probably require the use of macros though.

AMDG Mathias Gaunard <mathias.gaunard <at> etu.u-bordeaux1.fr> writes:
I don't know how boost.lambda actually does it, but on my x86 box, sizeof(_1 + a + b) yields 12, which means there is an overhead of one word for some reason.
_1 takes up space because lambda doesn't try to use EBO.
We are rather sure to have it well optimized if we do this though:
<snip>
It would be nice if we had a lambda engine that could automatically do such magic. This would probably require the use of macros though.
What you want is: template<class F> struct function_reference { function_reference(F& func) : f(boost::addressof(func)) {} template<class T...> decltype(make<F&>()(make<T>()...)) operator()(T&&... t) { return((*f)(t...)); } F* f; }; template<class F> function_reference<F> func_ref(F& f) { return(function_reference<F>(f)); } BOOST_AUTO(lambda, _1 + a + b); BOOST_AUTO(f, func_ref(lambda)); In Christ, Steven Watanabe

on Mon Aug 20 2007, "Giovanni Piero Deretta" <gpderetta-AT-gmail.com> wrote:
The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda.
Anyone would find such a mechanism useful? Alexander, do you think that it would be hard to extend ScopeExit to a generalized closure? I have done some experiments in the past with something like that and it seemed doable.
If it's really doable, I'd be very interested. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

Giovanni Piero Deretta <gpderetta <at> gmail.com> writes:
I use boost lambda expression extensively, and I have a love/hate relationship with them. When you finally get a (complex) lambda to compile it might even be elegant and even readable, but getting there requires an inordinate amount of time.
:-)
I do not have time right now for a review (I will try late this evening), but I think that the "inline" lambda capabilities of ScopeExit and its ScopeGuard-like functionality should be decoupled. The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda. Anyone would find such a mechanism useful? Alexander, do you think that it would be hard to extend ScopeExit to a generalized closure? I have done some experiments in the past with something like that and it seemed doable.
The problem is that ScopeExit relies on local structs which can't be used in templates. If you look at Implementation section ( http://tinyurl.com/2gerqy ) you'll notice params_1_t and scope_exit_body_t local structures. Though, I see how it can be avoided: (void*) new params_1_t(...). I should play with this idea. May be I'll be able to come up with a good syntax for a generalized closure ;-) -- Alexander

On 8/20/07, Alexander Nasonov <alnsn@yandex.ru> wrote:
Giovanni Piero Deretta <gpderetta <at> gmail.com> writes:
I use boost lambda expression extensively, and I have a love/hate relationship with them. When you finally get a (complex) lambda to compile it might even be elegant and even readable, but getting there requires an inordinate amount of time.
:-)
I do not have time right now for a review (I will try late this evening), but I think that the "inline" lambda capabilities of ScopeExit and its ScopeGuard-like functionality should be decoupled. The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda. Anyone would find such a mechanism useful? Alexander, do you think that it would be hard to extend ScopeExit to a generalized closure? I have done some experiments in the past with something like that and it seemed doable.
The problem is that ScopeExit relies on local structs which can't be used in templates.
If you look at Implementation section ( http://tinyurl.com/2gerqy ) you'll notice params_1_t and scope_exit_body_t local structures.
Though, I see how it can be avoided: (void*) new params_1_t(...).
Yep, or with virtual functions and a base class templated on the signature that forwards to the virtual. Tried both of tricks. Unfortunately gcc isn't capable of inlining either, so it is not very useful if you need to sqeeze out every bit of performance. On the other hand, 99% of the time you don't and syntactic sugar is really nice. I'll see if I can dig out some old code I have around and upload it in the vault.
I should play with this idea. May be I'll be able to come up with a good syntax for a generalized closure ;-)
yup! gpd

AMDG Giovanni Piero Deretta <gpderetta <at> gmail.com> writes:
The problem is that ScopeExit relies on local structs which can't be used in templates.
If you look at Implementation section ( http://tinyurl.com/2gerqy ) you'll notice params_1_t and scope_exit_body_t local structures.
Though, I see how it can be avoided: (void*) new params_1_t(...).
The local structs are not essential. You can use tuples. I too would definitely like to see something like int main() { int i = 0; BOOST_LOCAL_FUNCTION(f, (i), (int, v)) { i = v; } BOOST_LOCAL_FUNCTION_END; f(2); // i = 2 } In Christ, Steven Watanabe

On Mon, 20 Aug 2007 20:08:17 +0000 (UTC) Steven Watanabe <steven@providere-consulting.com> wrote:
The local structs are not essential. You can use tuples.
I too would definitely like to see something like
int main() {
int i = 0;
BOOST_LOCAL_FUNCTION(f, (i), (int, v)) { i = v; } BOOST_LOCAL_FUNCTION_END;
f(2); // i = 2
}
Steven, do you have time to submit a review of ScopeExit? Your experience and ideas would be most beneficial. Thanks!

AMDG Jody Hagins <jody-boost-011304 <at> atdesk.com> writes:
Steven, do you have time to submit a review of ScopeExit? Your experience and ideas would be most beneficial.
http://lists.boost.org/Archives/boost/2007/08/126065.php In Christ, Steven Watanabe

On Mon, 20 Aug 2007 20:49:14 +0000 (UTC) Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Jody Hagins <jody-boost-011304 <at> atdesk.com> writes:
Steven, do you have time to submit a review of ScopeExit? Your experience and ideas would be most beneficial.
Yeah, it was at the top of my list, and I missed it when I skimmed. Sorry about that. Thanks!

On 8/20/07, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Giovanni Piero Deretta <gpderetta <at> gmail.com> writes:
The problem is that ScopeExit relies on local structs which can't be used in templates.
If you look at Implementation section ( http://tinyurl.com/2gerqy ) you'll notice params_1_t and scope_exit_body_t local structures.
Though, I see how it can be avoided: (void*) new params_1_t(...).
The local structs are not essential. You can use tuples.
Well, you need local structures because you need to put the body of the closure somewhere. I'm attaching an experiment I have done a while ago. It is far from perfect, as it use gcc native typeof (could easily use BOOST_TYPEOF though), closure arity is limited to three arguments and you need to specify at least one closed-over variable. Also, you can't use commas in the closure body because I'm embedding it in a preprocessor sequence. Someone with more preprocessor-fu than me could easily overcome these limits though. The biggest limitation of this approach is that the generated function object is monomorphic (that is its argument types are fixed). BTW, it is little more than a curiosity, but by using gcc compound statements, true unnamed lambdas can be simulated quite well. HTH, gpd

Steven Watanabe <steven <at> providere-consulting.com> writes:
AMDG
The local structs are not essential. You can use tuples.
I like this idea.
I too would definitely like to see something like
int main() {
int i = 0;
BOOST_LOCAL_FUNCTION(f, (i), (int, v)) { i = v; } BOOST_LOCAL_FUNCTION_END;
f(2); // i = 2
}
How about this? int BOOST_LOCAL_FUNCTION( (v) ) (int i) { return v = i; } BOOST_LOCAL_FUNCTION_END You can think of it as if BOOST_LOCAL_FUNCTION macro invocation has been expanded to local function name. I'm not sure that it's possible in typeof emulation, though :( Here is how this construction looks after preprocessing: // Line 1. int (*sig_1)(); typedef typeof(v) typeof_v_1; typedef boost::tuple<typeof_v_1&> tuple_t_1; tuple_t_1 tuple_1(v); { // __LINE__ suffix can be omitted inside this block. typedef typeof(sig_1()) result_t; typedef tuple_t_1 tuple_t; tuple_t& tuple = tuple_1; struct scope_exit_body_t { typeof_v_1& v; scope_exit_body_t(tuple_t& tuple) : v(tuple.get<0>()) {} result_t // Lines 2-5. operator()(int i) const { return i = v; } // Line 6. }; typedef typeof(&scope_exit_body_t::operator()) native_typeof_only; }
In Christ, Steven Watanabe
-- Alexander

Steven Watanabe <steven <at> providere-consulting.com> writes: GMANE was down yesterday and I couldn't post anything except this message http://permalink.gmane.org/gmane.comp.lib.boost.devel/163948 but it didn't appear in the thread. -- Alexander

Giovanni Piero Deretta wrote:
I use boost lambda expression extensively, and I have a love/hate relationship with them. When you finally get a (complex) lambda to compile it might even be elegant and even readable, but getting there requires an inordinate amount of time.
There is one main issue with lambda: operator. cannot be overloaded. As a result, one must use bind, which is not only ugly but also requires you to explicitly write the type of what the placeholders are, which prevent generic visitation, for example. Another issue is that bind often prevents the compiler to inline the code. For example, #include <cstdio> struct Foo { int value; void display() const { std::printf("%d\n", value); } }; template<typename F> inline void apply(const F& f) { Foo foo = {42}; f(foo); } struct functor1 { void (Foo::*f)() const; functor1(void (Foo::*f_)() const) : f(f_) { } void operator()(const Foo& foo) const { (foo.*f)(); } }; struct functor2 { void operator()(const Foo& foo) const { foo.display(); } }; int main() { apply(functor1(&Foo::display)); apply(functor2()); } The first call won't be inlined with GCC, while the second call will. The first call is similar to what boost.bind generates. Note that LLVM is capable of inlining both.
I do not have time right now for a review (I will try late this evening), but I think that the "inline" lambda capabilities of ScopeExit and its ScopeGuard-like functionality should be decoupled.
The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda.
Lambda expressions will probably be built-in in the next standard anyway. Better work on implementing that in GCC. However, it could be useful to try to provide overloaded operator. using macros, and thus to allow to replace boost::bind by something better.

On 8/21/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
[...] Another issue is that bind often prevents the compiler to inline the code. For example,
[long code snipped]
The first call won't be inlined with GCC, while the second call will. The first call is similar to what boost.bind generates. Note that LLVM is capable of inlining both.
BTW, this is considered a bug in the GCC optimizer (gcc is perfectly capable to find out that the address is a constant, it simply doesn't run the inliner after constant propagation. There was a bugzilla entry about that, but I do not know if anybody did fix it yet).
I do not have time right now for a review (I will try late this evening), but I think that the "inline" lambda capabilities of ScopeExit and its ScopeGuard-like functionality should be decoupled.
The trick used by ScopeExit could be much more useful as a generalized (named) closure mechanism. These closures could then be used with the classic ScopeGuard idiom, to emulate what ScopeExit does right now, but could also replace most usages of boost lambda.
Lambda expressions will probably be built-in in the next standard anyway. Better work on implementing that in GCC.
Well, writing a ScopeExit like macro will take *far* less time than implementing lambdas in gcc. Especially if, like me, you know nothing of gcc internals and have no compiler experience. (BTW, the last lambda proposal looks very good)
However, it could be useful to try to provide overloaded operator. using macros, and thus to allow to replace boost::bind by something better.
This should be much easier. gpd
participants (10)
-
Alexander Nasonov
-
Christian Holmquist
-
David Abrahams
-
Giovanni Piero Deretta
-
Goran Mitrovic
-
Jody Hagins
-
Joseph Gauterin
-
Mathias Gaunard
-
Peder Holt
-
Steven Watanabe