Boost logo

Boost :

From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2023-11-30 21:11:33


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_at_[hidden]> 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_at_[hidden]> 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++.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk