[scope_exit] D-style scope(failure) and scope(success) in C++

Hello all, D language has scope(exit), scope(success) and scope(failure) features - http://dlang.org/statement.html#ScopeGuardStatement : "... scope(exit) executes NonEmptyOrScopeBlockStatement when the scope exits normally or when it exits due to exception unwinding. scope(failure) executes NonEmptyOrScopeBlockStatement when the scope exits due to exception unwinding. scope(success) executes NonEmptyOrScopeBlockStatement when the scope exits normally. ..." Andrei Alexandrescu describes some of uses cases for scope(exit), scope(success), scope(failure) at his recent talk : http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Succ... There is Boost.ScopeExit library which emulates D's scope(exit) via BOOST_SCOPE_EXIT macro, but there are no analogues for D's scope(failure) and scope(success). Current alternative for these features is ScopeGuard idiom ( http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard , http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/18440375... ). Boost.ScopeExit library itself suggests to use ScopeGuard - http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/scope_exit/alt... : " Boost.ScopeExit is similar to scope(exit) feature built into the D programming language. A curious reader may notice that the library does not implement scope(success) and scope(failure) of the D language. Unfortunately, these are not possible in C++ because failure or success conditions cannot be determined by calling std::uncaught_exception (see Guru of the Week #47 for details about std::uncaught_exception and if it has any good use at all). However, this is not a big problem because these two D's constructs can be expressed in terms of scope(exit) and a bool commit variable (similarly to some examples presented in the Tutorial section). " I have made small library ( https://github.com/panaseleus/stack_unwinding#d-style-scope-guardsactions ) which supplies primitives (class unwinding_indicator, UNWINDING_AWARE_DESTRUCTOR macro) to determining when object destructor is called due to stack-unwinding or due to normal scope leaving. Currently it is implemented on top of platform-specific implementation of uncaught_exception_count function and tested on: {MSVC2005, MSVC2008, MSVC2010, MSVC2012, GCC4.1.2, GCC4.4.6, Clang3.2}x{x32, x64}x{default settings}. uncaught_exception_count is a function similar to std::uncaught_exception from standard library, but instead of boolean result it returns unsigned int showing current count of uncaught exceptions. Such primitives allow us to implement scope(success) and scope(failure) features in C++. I have made several proof-of-concepts: * https://github.com/panaseleus/stack_unwinding/blob/master/examples/scope_act... * https://github.com/panaseleus/stack_unwinding/blob/master/examples/example_f... * https://github.com/panaseleus/stack_unwinding/blob/master/examples/scope_gua... * https://github.com/panaseleus/stack_unwinding/blob/master/examples/boost_sco... boost_scopes.cpp example shows usage of BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS: try { cout << "Case #1: stack unwinding" << endl; BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END throw 1; } catch(int){} { cout << "Case #2: normal exit" << endl; BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END } Output is: " Case #1: stack unwinding failure exit Case #2: normal exit success exit " Currently BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS are implemented based on boost_1_51_0/boost/scope_exit.hpp by copy-paste and replace (just for proof-or-concept, of course it is possible solution with much less duplication). Semantically meaningful changes can be viewed as diff at https://github.com/panaseleus/stack_unwinding/commit/d5513404323490ea99d9b6b... Before posting here, I made posts on several C++ forums, but unfortunately get only a few feedbacks regarding ScopeFailure and ScopeSuccess. What do you think? Thank you. P.S. Related discussion: http://lists.boost.org/Archives/boost/2010/09/171051.php Best Regards, Evgeny Panasyuk

Hi, This library seems very interresting. But you say that uncaught_exception_count() has flaws in your code. Can you give any exemple of the cases where your library can be fooled? thanks, ecyrbe 2012/10/2 Evgeny Panasyuk <evgeny.panasyuk@gmail.com>
Hello all,
D language has scope(exit), scope(success) and scope(failure) features - http://dlang.org/statement.**html#ScopeGuardStatement<http://dlang.org/statement.html#ScopeGuardStatement>: "... scope(exit) executes NonEmptyOrScopeBlockStatement when the scope exits normally or when it exits due to exception unwinding. scope(failure) executes NonEmptyOrScopeBlockStatement when the scope exits due to exception unwinding. scope(success) executes NonEmptyOrScopeBlockStatement when the scope exits normally. ..." Andrei Alexandrescu describes some of uses cases for scope(exit), scope(success), scope(failure) at his recent talk : http://channel9.msdn.com/**Events/Lang-NEXT/Lang-NEXT-** 2012/Three-Unlikely-**Successful-Features-of-D<http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Successful-Features-of-D>
There is Boost.ScopeExit library which emulates D's scope(exit) via BOOST_SCOPE_EXIT macro, but there are no analogues for D's scope(failure) and scope(success). Current alternative for these features is ScopeGuard idiom ( http://en.wikibooks.org/wiki/**More_C%2B%2B_Idioms/Scope_**Guard<http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard>, http://www.drdobbs.com/cpp/**generic-change-the-way-you-** write-excepti/184403758<http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758>).
Boost.ScopeExit library itself suggests to use ScopeGuard - http://www.boost.org/doc/libs/**1_51_0/libs/scope_exit/doc/** html/scope_exit/alternatives.**html#scope_exit.alternatives.** the_d_programming_language<http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/scope_exit/alternatives.html#scope_exit.alternatives.the_d_programming_language>: " Boost.ScopeExit is similar to scope(exit) feature built into the D programming language. A curious reader may notice that the library does not implement scope(success) and scope(failure) of the D language. Unfortunately, these are not possible in C++ because failure or success conditions cannot be determined by calling std::uncaught_exception (see Guru of the Week #47 for details about std::uncaught_exception and if it has any good use at all). However, this is not a big problem because these two D's constructs can be expressed in terms of scope(exit) and a bool commit variable (similarly to some examples presented in the Tutorial section). "
I have made small library ( https://github.com/panaseleus/** stack_unwinding#d-style-scope-**guardsactions<https://github.com/panaseleus/stack_unwinding#d-style-scope-guardsactions>) which supplies primitives (class unwinding_indicator, UNWINDING_AWARE_DESTRUCTOR macro) to determining when object destructor is called due to stack-unwinding or due to normal scope leaving. Currently it is implemented on top of platform-specific implementation of uncaught_exception_count function and tested on: {MSVC2005, MSVC2008, MSVC2010, MSVC2012, GCC4.1.2, GCC4.4.6, Clang3.2}x{x32, x64}x{default settings}. uncaught_exception_count is a function similar to std::uncaught_exception from standard library, but instead of boolean result it returns unsigned int showing current count of uncaught exceptions.
Such primitives allow us to implement scope(success) and scope(failure) features in C++. I have made several proof-of-concepts: * https://github.com/panaseleus/**stack_unwinding/blob/master/** examples/scope_actions.cpp<https://github.com/panaseleus/stack_unwinding/blob/master/examples/scope_actions.cpp> * https://github.com/panaseleus/**stack_unwinding/blob/master/** examples/example_from_dlang_**dot_org.cpp<https://github.com/panaseleus/stack_unwinding/blob/master/examples/example_from_dlang_dot_org.cpp> * https://github.com/panaseleus/**stack_unwinding/blob/master/** examples/scope_guard.cpp<https://github.com/panaseleus/stack_unwinding/blob/master/examples/scope_guard.cpp> * https://github.com/panaseleus/**stack_unwinding/blob/master/** examples/boost_scopes.cpp<https://github.com/panaseleus/stack_unwinding/blob/master/examples/boost_scopes.cpp>
boost_scopes.cpp example shows usage of BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS: try { cout << "Case #1: stack unwinding" << endl; BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END throw 1; } catch(int){} { cout << "Case #2: normal exit" << endl; BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END } Output is: " Case #1: stack unwinding failure exit Case #2: normal exit success exit "
Currently BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS are implemented based on boost_1_51_0/boost/scope_exit.**hpp by copy-paste and replace (just for proof-or-concept, of course it is possible solution with much less duplication). Semantically meaningful changes can be viewed as diff at https://github.com/panaseleus/**stack_unwinding/commit/** d5513404323490ea99d9b6b77ff1b8**8f454a4a42<https://github.com/panaseleus/stack_unwinding/commit/d5513404323490ea99d9b6b77ff1b88f454a4a42>
Before posting here, I made posts on several C++ forums, but unfortunately get only a few feedbacks regarding ScopeFailure and ScopeSuccess. What do you think?
Thank you.
P.S. Related discussion: http://lists.boost.org/** Archives/boost/2010/09/171051.**php<http://lists.boost.org/Archives/boost/2010/09/171051.php>
Best Regards, Evgeny Panasyuk
______________________________**_________________ Unsubscribe & other changes: http://lists.boost.org/** mailman/listinfo.cgi/boost<http://lists.boost.org/mailman/listinfo.cgi/boost>

Hello,
This library seems very interresting. But you say that uncaught_exception_count() has flaws in your code. Can you give any exemple of the cases where your library can be fooled?
As far as I know, uncaught_exception_count itself does not have flaws. There is some flaw in unwinding_indicator based on uncaught_exception_count. It works as follows: 1. store uncaught_exception_count in constructor 2. member function unwinding() returns true if state stored in constructor does not equals to current uncaught_exception_count. I.e. returns true on transition of state. It can be fooled in following case: when object is created during stack unwinding (i.e. in some destructor), and that object outlived unwinding process, for instance it was stored in global variable. I have just added example to repo showing such case: https://github.com/panaseleus/stack_unwinding/blob/master/examples/uncaught_... (it has output at bottom) . As you can see there is transition in uncaught_exception_count state, butdestructor ( ~ExpCountPrinter() ) is not called due to unwinding. However, despite of this flaw, scope(failure) and scope(success) features can be reliably implemented on top of such unwinding_indicator, because it's objects live only in code blocks (compound-statements), and can't leave them. Especially in case of proposed BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS - user even don't see auxiliary variables. Thank you! Best Regards, Evgeny

It can be fooled in following case: when object is created during stack unwinding (i.e. in some destructor), and that object outlived unwinding process, for instance it was stored in global variable. I have just added example to repo showing such case: https://github.com/panaseleus/**stack_unwinding/blob/master/** examples/uncaught_exception_**count_floating_object.cpp<https://github.com/panaseleus/stack_unwinding/blob/master/examples/uncaught_exception_count_floating_object.cpp>(it has output at bottom) . As you can see there is transition in uncaught_exception_count state, butdestructor ( ~ExpCountPrinter() ) is not called due to unwinding.
Thank you, i understand better now.
However, despite of this flaw, scope(failure) and scope(success) features can be reliably implemented on top of such unwinding_indicator, because it's objects live only in code blocks (compound-statements), and can't leave them. Especially in case of proposed BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS - user even don't see auxiliary variables.
i'll test it further.. But i think that this should be included in boost. Maybe this library could be added to boost by submitting a patch to scope_exit library? or by requesting a mini-review? thank you very much for your work. ecyrbe

Hello,
i'll test it further.. But i think that this should be included in boost. Maybe this library could be added to boost by submitting a patch to scope_exit library? or by requesting a mini-review? I think scope(failure) and scope(success) features should be placed to Boost.ScopeExit library (I guess like a patch).
But I am not sure about unwinding_indicator/uncaught_exception_count - maybe they should be placed into Boost.Exception? At which scope? PUBLIC (users of library may use it) or DETAIL(can be used by other Boost libraries but not outside Boost) scopes of Boost.Exception? Or maybe at AUX("private" symbols that shall be used only within this library) scope of Boost.ScopeExit? Best Regards, Evgeny Panasyuk

But I am not sure about unwinding_indicator/uncaught_exception_count - maybe they should be placed into Boost.Exception? At which scope? PUBLIC (users of library may use it) or DETAIL(can be used by other Boost libraries but not outside Boost) scopes of Boost.Exception? Or maybe at AUX("private" symbols that shall be used only within this library) scope of Boost.ScopeExit?
I don't have any answer for this. May be try to contact lorenzo Caminiti, the maintainer of boost scope exit, directly to know what he thinks of your proposal. regards, ecyrbe

Hello,
There is Boost.ScopeExit library which emulates D's scope(exit) via BOOST_SCOPE_EXIT macro, but there are no analogues for D's scope(failure) and scope(success).
I have just checked Boost.ScopeExit on-line manual (http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/index.html). Approximately 14 of 16 BOOST_SCOPE_EXIT* samples in manual are in fact emulations of SCOPE_FAILURE and SCOPE_SUCCESS. So, looks like in first place Boost.ScopeExit was introduced to simplify emulation of scope(failure) and scope(success) features. For instance first example: void world::add_person(person const& a_person) { bool commit = false; persons_.push_back(a_person); BOOST_SCOPE_EXIT(&commit, &persons_) { if(!commit) persons_.pop_back(); } BOOST_SCOPE_EXIT_END // ... commit = true; } Can be re-implemented with SCOPE_FAILURE https://github.com/panaseleus/stack_unwinding#d-style-scope-guardsactions in following way: void world::add_person(person const& a_person) { persons_.push_back(a_person); SCOPE_FAILURE(&persons_) { persons_.pop_back(); } SCOPE_FAILURE_END // ... } Best Regards, Evgeny

10.10.2012 23:47, Evgeny Panasyuk пишет:
I have just checked Boost.ScopeExit on-line manual (http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/index.html). Approximately 14 of 16 BOOST_SCOPE_EXIT* samples in manual are in fact emulations of SCOPE_FAILURE and SCOPE_SUCCESS.
Yes, SCOPE_FAILURE seems to be useful. But could you please provide an use case for the SCOPE_SUCCESS? It seems to me that it is better to place SUCCESS code at the end of the scope. Note also that the exceptions cannot be thrown from the SCOPE_SUCCESS. -- Best regards, Sergey Cheban

Hello, 11.10.2012 2:31, Sergey Cheban wrote:
10.10.2012 23:47, Evgeny Panasyuk wrote:
I have just checked Boost.ScopeExit on-line manual (http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/index.html).
Approximately 14 of 16 BOOST_SCOPE_EXIT* samples in manual are in fact emulations of SCOPE_FAILURE and SCOPE_SUCCESS.
Yes, SCOPE_FAILURE seems to be useful. But could you please provide an use case for the SCOPE_SUCCESS? It seems to me that it is better to place SUCCESS code at the end of the scope.
1. Besides exceptions, there are different ways to create several ends of scope. For instance, code block may has several returns, breaks, continues. So, there is not one end of scope - there are several. Placing SUCCESS code manually to every end of scope is error prone (as well as commit=true for ScopeGuards). While code within BOOST_SCOPE_EXIT/SCOPE_SUCCESS/SCOPE_FAILURE executes (or not, depending on exceptions state) at every end on scope. Example: { SCOPE_FAILURE(void) { log("could not update user info"); } SCOPE_FAILURE_END File passwd("/etc/passwd"); SCOPE_SUCCESS( (&passwd) ) { passwd.flush(); } SCOPE_SUCCESS_END BOOST_SCOPE_EXIT( (&passwd) ) { passwd.close(); } BOOST_SCOPE_EXIT_END // ... - may contain several returns, etc } 2. SCOPE_SUCCESS can be scheduled to real end of scope, after all destructors which may throw, after all other SCOPE_SUCCESS scheduled after it which also may throw. it is impossible to place manual actions somewhere between or after destructor calls, without use of artificial C++ code blocks: void some_func() { // Artificial code block { Something a,b,c; /* ... */ } SUCCESS_ACTION; } Using SCOPE_SUCCESS it will become: void some_func() { SCOPE_SUCCESS(void) { SUCCESS_ACTION; } SCOPE_SUCCESS_END Something a,b,c; /* ... */ } 3. Andrei Alexandrescu mentioned D's scope(success) at his recent talk http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Succ... : "[description of scope(failure) and scope(exit)]... There is rarely used variant for completion, which is scope(success). And then you celebrate, there is orchestra, fireworks if you wish. It is not very often used, but people use it sometimes and it turns out that it defers completion"
Note also that the exceptions cannot be thrown from the SCOPE_SUCCESS.
Why? Conversely it is pretty safe to throw exception from SCOPE_SUCCESS. "passwd.flush();" above may safely throw on fail. P.S. I think that having SCOPE_SUCCESS like feature "inside" objects would be useful. For instance, from the 2. example above, there is "File passwd". We can use RAII and place BOOST_SCOPE_EXIT's passwd.close(); into File's destructor: { SCOPE_FAILURE(void) { log("could not update user info"); } SCOPE_FAILURE_END File passwd("/etc/passwd"); SCOPE_SUCCESS( (&passwd) ) { passwd.flush(); } SCOPE_SUCCESS_END // passwd.~File() calls close() } But currently, we don't tool have tool for get rid of SCOPE_SUCCESS's passwd.flush(), i.e. deferred action. Current guideline is to call such actions manually. I came up with notion of two-stage destructor which consist of two parts: deferred action (may throw) and release action(should not throw, never fail). Where deferred action is executed only when object is destructed not due to stack unwinding - and such action may safely throw. And release action is executed in any case. https://github.com/panaseleus/stack_unwinding#two-stage-destructor Current syntax is: class RAII_Deferred { bool fail_on_flush; public: RAII_Deferred(bool fail_on_flush_) : fail_on_flush(fail_on_flush_) { cout << "acquiring resource" << endl; } TWO_STAGE_DESTRUCTOR_RELEASE(RAII_Deferred) { cout << "release resource" << endl; } // Deferred part of destructor. May fail(for instance fflush). TWO_STAGE_DESTRUCTOR_DEFERRED(RAII_Deferred) { cout << "flush pending actions on resource" << endl; if(fail_on_flush) throw 1; } }; So, with such tool, we may have following File object: { SCOPE_FAILURE(void) { log("could not update user info"); } SCOPE_FAILURE_END File passwd("/etc/passwd"); //passwd.~Deferred() callsflush(), when called not due to stack unwinding abd may safely throw // passwd.~File() calls close() } Best Regards, Evgeny

On 02.10.2012 16:53, Evgeny Panasyuk wrote:
Currently BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS are implemented based on boost_1_51_0/boost/scope_exit.hpp by copy-paste and replace (just for proof-or-concept, of course it is possible solution with much less duplication). Semantically meaningful changes can be viewed as diff at https://github.com/panaseleus/stack_unwinding/commit/d5513404323490ea99d9b6b... Any progress on this?
-- Sergey Cheban

On Thu, Sep 26, 2013 at 5:58 AM, Sergey Cheban <s.cheban@drweb.com> wrote:
On 02.10.2012 16:53, Evgeny Panasyuk wrote:
Currently BOOST_SCOPE_FAILURE and BOOST_SCOPE_SUCCESS are implemented based on boost_1_51_0/boost/scope_exit.hpp by copy-paste and replace (just for proof-or-concept, of course it is possible solution with much less duplication). Semantically meaningful changes can be viewed as diff at
https://github.com/panaseleus/stack_unwinding/commit/d5513404323490ea99d9b6b...
Any progress on this?
As far as I understand it, this cannot be implemented (at least in a portable way). See: http://www.boost.org/doc/libs/1_54_0/libs/scope_exit/doc/html/scope_exit/alt... Boost.ScopeExit is similar to scope(exit) feature built into the D programming language. A curious reader may notice that the library does not implement scope(success) and scope(failure) of the D language. Unfortunately, these are not possible in C++ because failure or success conditions cannot be determined by callingstd::uncaught_exception (see Guru of the Week #47 for details about std::uncaught_exception and if it has any good use at all). However, this is not a big problem because these two D's constructs can be expressed in terms of scope(exit) and a boolcommit variable (similarly to some examples presented in the Tutorial section). HTH, --Lorenzo

27.09.2013 1:55, Lorenzo Caminiti:
Any progress on this?
As far as I understand it, this cannot be implemented (at least in a portable way). See:
I have made platform-specific implementation: https://github.com/panaseleus/stack_unwinding. It is tested it on {Clang 3.2, GCC 3.4.6, GCC 4.1.2, GCC 4.4.6, GCC 4.4.7, MSVC2005SP1, MSVC2008SP1, MSVC2010SP1, MSVC2012} x {x32, x64} and some others - which fulfils Boost portability requirements( http://www.boost.org/development/requirements.html#Portability ): " A library's implementation must if possible be portable and not restricted to a particular compiler or operating system. If a portable implementation is not possible, non-portable constructions are acceptable if reasonably easy to port to other environments, and implementations are provided for at least two popular operating systems (such as UNIX and Windows). " I have posted it here twice to different libraries with no success: 1. [boost][scope_exit]: http://boost.2283326.n4.nabble.com/scope-exit-D-style-scope-failure-and-scop... 2. [boost][exception]: http://boost.2283326.n4.nabble.com/exception-uncaught-exception-count-scope-... It is partly included in Boost.Log since 1.54: http://ci.boost.org/svn-trac/browser/trunk/libs/log/src/unhandled_exception_... . But for the purposes of scope(failure) and scope(success) it is preferable to put it as header-only. If library maintainer of [exception] or [scope_exit] would agree to integrate uncaught_exception_count - then we may be lucky to get it released in 1.56. -- Evgeny Panasyuk

On Thu, Sep 26, 2013 at 3:39 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
If library maintainer of [exception] or [scope_exit] would agree to integrate uncaught_exception_count - then we may be lucky to get it released in 1.56.
I don't understand what does "integrate" mean in this case. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

27.09.2013 2:45, Emil Dotchevski:
On Thu, Sep 26, 2013 at 3:39 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
If library maintainer of [exception] or [scope_exit] would agree to integrate uncaught_exception_count - then we may be lucky to get it released in 1.56.
I don't understand what does "integrate" mean in this case.
Would like to see it as part of appropriate library. -- Evgeny Panasyuk

On Thu, Sep 26, 2013 at 3:51 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
27.09.2013 2:45, Emil Dotchevski:
On Thu, Sep 26, 2013 at 3:39 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
If library maintainer of [exception] or [scope_exit] would agree to integrate uncaught_exception_count - then we may be lucky to get it released in 1.56.
I don't understand what does "integrate" mean in this case.
Would like to see it as part of appropriate library.
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception? -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

27.09.2013 3:08, Emil Dotchevski:
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception?
There are two parts: 1. function uncaught_exception_count 2. scope(failure) and scope(success) which are built on top of uncaught_exception_count I have in mind two approaches: a) Add both into Boost.ScopeExit or b) As a first step add uncaught_exception_count into Boost.Exception - as it is closely related to it's theme. And then scope(failure)/scope(success) will go into Boost.ScopeExit. At that message - http://boost.2283326.n4.nabble.com/exception-uncaught-exception-count-scope-... - there is link to proposal by Herb Sutter about similar functionality. -- Evgeny Panasyuk

On Thu, Sep 26, 2013 at 4:20 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
27.09.2013 3:08, Emil Dotchevski:
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception?
There are two parts: 1. function uncaught_exception_count 2. scope(failure) and scope(success) which are built on top of uncaught_exception_count
I have in mind two approaches: a) Add both into Boost.ScopeExit or b) As a first step add uncaught_exception_count into Boost.Exception - as it is closely related to it's theme. And then scope(failure)/scope(success) will go into Boost.ScopeExit.
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure? -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Thursday 26 September 2013 16:24:21 Emil Dotchevski wrote:
On Thu, Sep 26, 2013 at 4:20 PM, Evgeny Panasyuk
<evgeny.panasyuk@gmail.com> wrote:
27.09.2013 3:08, Emil Dotchevski:
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception?
There are two parts: 1. function uncaught_exception_count 2. scope(failure) and scope(success) which are built on top of uncaught_exception_count
I have in mind two approaches: a) Add both into Boost.ScopeExit or b) As a first step add uncaught_exception_count into Boost.Exception - as it is closely related to it's theme. And then scope(failure)/scope(success) will go into Boost.ScopeExit.
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure?
In Boost.Log, I use it to implement my own guard objects which must perform some finalizing work at destructor. With uncaught_exception_count I am able to detect whether the destructor is invoked as a result of an exception and cancel the work. uncaught_exception_count is an improvement of std::uncaught_exception. IMHO, its place is Boost.Exception.

On Thu, Sep 26, 2013 at 11:37 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
On Thursday 26 September 2013 16:24:21 Emil Dotchevski wrote:
On Thu, Sep 26, 2013 at 4:20 PM, Evgeny Panasyuk
<evgeny.panasyuk@gmail.com> wrote:
27.09.2013 3:08, Emil Dotchevski:
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception?
There are two parts: 1. function uncaught_exception_count 2. scope(failure) and scope(success) which are built on top of uncaught_exception_count
I have in mind two approaches: a) Add both into Boost.ScopeExit or b) As a first step add uncaught_exception_count into Boost.Exception - as it is closely related to it's theme. And then scope(failure)/scope(success) will go into Boost.ScopeExit.
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure?
In Boost.Log, I use it to implement my own guard objects which must perform some finalizing work at destructor. With uncaught_exception_count I am able to detect whether the destructor is invoked as a result of an exception and cancel the work.
Isn't this the same use case as scope-failure? (I don't buy the "must" in "finalizing work in a destructor" but that's the same as scope-failure, too.) -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Friday 27 September 2013 00:23:08 Emil Dotchevski wrote:
On Thu, Sep 26, 2013 at 11:37 PM, Andrey Semashev
<andrey.semashev@gmail.com> wrote:
On Thursday 26 September 2013 16:24:21 Emil Dotchevski wrote:
On Thu, Sep 26, 2013 at 4:20 PM, Evgeny Panasyuk
<evgeny.panasyuk@gmail.com> wrote:
27.09.2013 3:08, Emil Dotchevski:
Perhaps I'm missing something, but if it is a facility that aids the scope_exit library, it should be part of the scope_exit library. Do you feel that it should be part of Boost Exception?
There are two parts: 1. function uncaught_exception_count 2. scope(failure) and scope(success) which are built on top of uncaught_exception_count
I have in mind two approaches: a) Add both into Boost.ScopeExit or b) As a first step add uncaught_exception_count into Boost.Exception - as it is closely related to it's theme. And then scope(failure)/scope(success) will go into Boost.ScopeExit.
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure?
In Boost.Log, I use it to implement my own guard objects which must perform some finalizing work at destructor. With uncaught_exception_count I am able to detect whether the destructor is invoked as a result of an exception and cancel the work.
Isn't this the same use case as scope-failure?
The guard object in Boost.Log is not a scope guard but is a temporary object. But the use of uncaught_exception_count is very similar. I cannot reuse scope_exit(success) if you imply that.

27.09.2013 3:24, Emil Dotchevski:
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure?
scope(failure)/scope(success) would be main use case, however - there are several others: 1. scope(failure/success) runs specified code block. Sometimes such code block can be reused - in that case custom guard object is preferred over copy-pasting code. 2. Temporary objects: log() << may_throw() << endl; log() returns some temporary object which does some finalizing work in destructor. If that destructor is called due to stack unwinding - then finalizing part will be different. I think Andrey Semashev has something similar at Boost.Log. 3. Stack objects which do work in destructor that may fail. Traditional example is File object which requires flush(may fail) and release handle at the end of lifetime. Typical solution is to place .flush() manually and release handle in destructor: { File a,b; // ... b.flush(); // may throw a.flush(); // may throw } If b.flush() will throw then a.flush() will not happen but only release of file handle at a.~File(). Same effect can be achieved automatically using uncaught_exception_count/unwinding_indicator: { File a,b; // ... // conditional flush of b and a in destructors. } -- Evgeny Panasyuk

On Sun, Sep 29, 2013 at 2:23 PM, Evgeny Panasyuk <evgeny.panasyuk@gmail.com> wrote:
27.09.2013 3:24, Emil Dotchevski:
Is there a use case for uncaught_exception_count other than to implement D-style scope-exit/-failure?
scope(failure)/scope(success) would be main use case, however - there are several others:
1. scope(failure/success) runs specified code block. Sometimes such code block can be reused - in that case custom guard object is preferred over copy-pasting code.
That is still the scope failure use case, which presumably has to deal with exceptions in the failure branch. I don't object to scope exit/failure dealing with exceptions any way its designers think it should.
2. Temporary objects: log() << may_throw() << endl; log() returns some temporary object which does some finalizing work in destructor. If that destructor is called due to stack unwinding - then finalizing part will be different.
Here, if may_throw() throws, ~log() must not throw. Therefore it is possible for the user to not be notified about a logging failure. If it is critical for the user to be notified about all logging failures, then then ~log() must not do any logging. How critical this notification is doesn't depend on whether or not may_throw() emits an exception.
3. Stack objects which do work in destructor that may fail. Traditional example is File object which requires flush(may fail) and release handle at the end of lifetime. Typical solution is to place .flush() manually and release handle in destructor: { File a,b; // ... b.flush(); // may throw a.flush(); // may throw }
The motivation here is to support throwing destructors. This becomes a self-fulfilling prophecy: you write destructors that may throw, which forces everyone else to deal with that. It is incorrect for objects that are no longer needed to be able to fail to go away, therefore destructors must not throw. So, I'd consider flush()ing elsewhere. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

30.09.2013 2:55, Emil Dotchevski:
1. scope(failure/success) runs specified code block. Sometimes such code block can be reused - in that case custom guard object is preferred over copy-pasting code.
That is still the scope failure use case, which presumably has to deal with exceptions in the failure branch.
What do you mean? Every use case of uncaught_exception_count has to deal something with exceptions. And yes, that use case is similar to scope(failure/success), but it cannot be implemented on top of it. In order to implement it user need a tool: uncaught_exception_count/unwinding_indicator. And I think that tool is closer to Boost.Exception than to Boost.ScopeExit.
2. Temporary objects: log() << may_throw() << endl; log() returns some temporary object which does some finalizing work in destructor. If that destructor is called due to stack unwinding - then finalizing part will be different.
Here, if may_throw() throws, ~log() must not throw. Therefore it is possible for the user to not be notified about a logging failure. If it is critical for the user to be notified about all logging failures, then then ~log() must not do any logging. How critical this notification is doesn't depend on whether or not may_throw() emits an exception.
It is not only about logging. Temporary object may do some job related to invariants. For instance it can be used to get "strong guarantee" in some cases: may_throw( x.temp_inner_invariant() ); destructor of object returned by temp_inner_invariant can restore original state on exception from may_throw. Or it can be opposite - do some invariant keeping job on success and do nothing on failure (or maybe replace inner data with cheap default to get something like "basic guarantee"). Concrete example: suppose we have class UnsafeString: class UnsafeString { vector<char> data; size_t length; ... invariant is length == strlen(&data[0]); Such string can be filled by API which accepts only char* in following way: UnsafeString s; unsafe_api( s.get_buffer(1024) ); get_buffer returns auxiliary wrapper which implicitly converts to char* and in destructor maintains invariant of UnsafeString. If unsafe_api would throw exception - then auxiliary wrapper can use unwinding_indicator to spot it and select appropriate approach (restore to original or restore to cheap default value).
3. Stack objects which do work in destructor that may fail. Traditional example is File object which requires flush(may fail) and release handle at the end of lifetime. Typical solution is to place .flush() manually and release handle in destructor: { File a,b; // ... b.flush(); // may throw a.flush(); // may throw }
The motivation here is to support throwing destructors. This becomes a self-fulfilling prophecy: you write destructors that may throw, which forces everyone else to deal with that.
I am talking about throwing only from destructors of stack objects. There are many reasons to not throw from objects which are part of others, for instance from element of std::vector or from element of plain array. I do not offer to throw from every kind of destructor. But it is OK to throw from desctructor of "stack object" as long as you do that conditionally based on unwinding indicator. That can be controversial - but it is just one of examples of unwinding indicator usage. It is up to developer to decide whenever use it or not.
It is incorrect for objects that are no longer needed to be able to fail to go away, therefore destructors must not throw.
Why? Semantically it is exactly same to placing flush by hands. -- Evgeny Panasyuk

On Sunday 29 September 2013 15:55:01 Emil Dotchevski wrote:
On Sun, Sep 29, 2013 at 2:23 PM, Evgeny Panasyuk
<evgeny.panasyuk@gmail.com> wrote:
2. Temporary objects: log() << may_throw() << endl; log() returns some temporary object which does some finalizing work in destructor. If that destructor is called due to stack unwinding - then finalizing part will be different.
Here, if may_throw() throws, ~log() must not throw. Therefore it is possible for the user to not be notified about a logging failure. If it is critical for the user to be notified about all logging failures, then then ~log() must not do any logging. How critical this notification is doesn't depend on whether or not may_throw() emits an exception.
In case of Boost.Log, ~log() would actually push the log record to the library for processing (applying final formatting, writing to files/console, etc.). If the streaming statement fails with an exception, ~log() must not do anything and let the exception propagate. OTOH, when the streaming expression completes normally, the record processing may throw itself, which makes ~log() a throwing destructor. So you see, no errors are lost, but in some cases work must be suppressed for correct behavior. Writing throwing destructors is discouraged, everyone knows that. But sometimes you just need it because it offers benefits compared to other approaches. unhandled_exception_count() is crucial to make that possible. There are restrictions for such classes, e.g. they should not be used as members of other classes or allocated on heap. But log() above is never intended to be used that way.

On Sun, Sep 29, 2013 at 8:53 PM, Andrey Semashev <andrey.semashev@gmail.com> wrote:
On Sunday 29 September 2013 15:55:01 Emil Dotchevski wrote:
On Sun, Sep 29, 2013 at 2:23 PM, Evgeny Panasyuk Writing throwing destructors is discouraged, everyone knows that. But sometimes you just need it because it offers benefits compared to other approaches.
It also has drawbacks. :) Perhaps "need" is an overstatement here, I'm sure there are other ways to do this even if we insist on using the same syntax. I didn't intend to create an argument, but I think that it is a mistake to open this Pandora's box, so I don't want to provide support for it in the exception library. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sunday 29 September 2013 21:55:44 Emil Dotchevski wrote:
On Sun, Sep 29, 2013 at 8:53 PM, Andrey Semashev
<andrey.semashev@gmail.com> wrote:
On Sunday 29 September 2013 15:55:01 Emil Dotchevski wrote:
On Sun, Sep 29, 2013 at 2:23 PM, Evgeny Panasyuk
Writing throwing destructors is discouraged, everyone knows that. But sometimes you just need it because it offers benefits compared to other approaches.
It also has drawbacks. :)
Perhaps "need" is an overstatement here, I'm sure there are other ways to do this even if we insist on using the same syntax.
I didn't intend to create an argument, but I think that it is a mistake to open this Pandora's box, so I don't want to provide support for it in the exception library.
Ok. In that case, how about making unhandled_exception_count() a member of boost/detail, so that multiple libraries can use it?

30.09.2013 8:55, Emil Dotchevski:
Writing throwing destructors is discouraged, everyone knows that. But sometimes you just need it because it offers benefits compared to other approaches.
It also has drawbacks. :)
Perhaps "need" is an overstatement here, I'm sure there are other ways to do this even if we insist on using the same syntax.
If that is possible then scope(failure/success) also can be implemented in that way (without unwinding_indicator). Many have tried to do that in portable C++ with no success.
I didn't intend to create an argument, but I think that it is a mistake to open this Pandora's box, so I don't want to provide support for it in the exception library.
1. Throwing destructors is just one use case for scope(success)-like objects. But there are other use cases with scope(failure)-like objects which do not throw anything from destructor. 2. There is ISO proposal by Herb Sutter - http://isocpp.org/files/papers/N3614.pdf - for adding similar functionality: std::unwinding_exception(). 3. There is article by Jon Kalb and Dave Abrahams regarding throwing destructors: "Evil, or Just Misunderstood?" http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/ -- Evgeny Panasyuk
participants (6)
-
Andrey Semashev
-
ecyrbe
-
Emil Dotchevski
-
Evgeny Panasyuk
-
Lorenzo Caminiti
-
Sergey Cheban