On 11/30/23 23:39, Janko Dedic via Boost wrote:
On Thu, Nov 30, 2023 at 4:52 PM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 11/30/23 00:35, Janko Dedic via Boost wrote:
On Wed, Nov 29, 2023 at 4:56 PM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
I don't see the current definition of BOOST_SCOPE_FINAL as a deficiency of the interface compared to passing the capture list in the macro arguments. The latter doesn't offer any advantages compared to the current definition, and in fact is more limiting as it only allows for lambda functions for the scope guard action.
It offers better syntax.
Better in what way, other than your personal preference? Can you describe objective advantages of your proposed syntax and why the current BOOST_SCOPE_FINAL doesn't work for you?
Better because the user is not forced to type the capture list everywhere. Ideally we would not even require a semicolon at the end, but we can't get rid of that. The ideal is a core language construct like Go's defer or D's scope(exit).
If typing [&] is a problem, you could just #define SCOPE_GUARD BOOST_SCOPE_FINAL [&] and use that. Personally, I have no problem with the capture list, and quite often I actually use capture lists more elaborate than [&].
I only suggested adding [&] to the macro, or adding a macro that includes the [&].
Sorry, but no. That would limit user's options for no reason, and binding variables by value is not uncommon. Users of Boost.Scope should have the full range of function object definition ways that is permitted by the language.
And why is having these options useful?
Because I found it useful in my practice. I do regularly capture variables by value and use initializers in capture lists. I already mentioned noexcept and specifying non-lambda function objects as a way to reduce code duplication.
Note that the user can still use the constructor or the factory function directly to fully customize the behavior (if they want to for whatever reason). I can understand your motivation behind this macro (declaring an anonymous scope guard variable only), but in 99% of cases I would personally end up using BOOST_SCOPE_FINAL [&], and I don't understand why the library wouldn't provide such a macro (Alexandrescu's original SCOPE_EXIT works like this).
Because, IMO, the cost of typing [&] does not outweigh the cost of losing other features that I mentioned. If that is not the case for you, you can always define your own macro.
If you want to enforce that your action never throws, you can declare its operator() as noexcept:
BOOST_SCOPE_FINAL []() noexcept { /* I guarantee I won't throw */ };
Does anyone really want to write code like this?
I see nothing wrong with this code. I actually wrote code like this, where the no-throw guarantee was important.
It just looks like a weird macro incantation to me personally. SCOPE_EXIT { run(); }; at least tried to model a control flow construct, even though there's the unfortunate semicolon at the end. I strive to have the least amount of clever macros possible in my code.
I'm not trying to pretend that scope guards are a control flow structure. Because they are not, they are a declaration. At least, in current C++.