C++ Logo

std-discussion

Advanced search

Re: Some feedback on scope guards

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Sat, 8 Apr 2023 13:55:49 +0300
On 4/8/23 03:54, Thiago Macieira via Std-Discussion wrote:
> On Friday, 7 April 2023 20:53:56 -03 Andrey Semashev via Std-Discussion wrote:
>
>>> For most cases, this can be implemented already, with the ability to
>>> deactivate a scope, because the typical use of such guards is to have them
>>> execute on early returns. At the moment when we've achieved success, it
>>> can be then dismissed -- compiler optimisations detecting such conditions
>>> would be welcome too.
>>
>> This would be error-prone if there are multiple successful (or failure)
>> return points. Scope guards are specifically aimed to relieve you from
>> having to worry about missing the action upon leaving the scope, and
>> having to manually (de)activate the guard before returning goes against
>> this goal.
>
> I disagree that it is error-prone. So long as all the early returns (including
> throws) are of the same category -- either success or failure -- then you
> simply keep the guard active, until the point when you've assured success. At
> that point, you simply dismiss it.

Think about code maintenance. Will your coworker (or you, after not
looking into the code for a few months) not forget to deactivate the
scope guard when he adds a new return in the middle of the function?
IMHO, if the scope guard requires manual maintenance at scope exit
points then the scope guard is not fulfilling its purpose.

>> This is also the case for other common cases, like testing whether an
>> error code indicates error. The condition function need not be a lambda,
>> it can be a function object that is written once and then reused in
>> multiple scope guards.
>
> Such an object can simply be captured and queried inside the lambda of the
> guard action.
>
> I understand the convenience value, but I am questioning whether it's worth
> the cost for implementers as well as the cognitive load for users: will they
> remember to use this variant instead of the generic one?

If implementers already have to implement scope_success/scope_fail for
the exceptions case, it is fairly simple to extend it to support
arbitrary failure conditions. And from the user's perspective, an
exception does not need to be the only failure condition. Indeed, there
are code bases that actively avoid exceptions - scope_success/scope_fail
would be useless there if they don't support other ways to indicate failure.

Whether the user remembers to use scope_success/scope_fail, I don't
know, that kind of question seems too abstract. Speaking for myself, I
know that once I learned scope_exit/scope_success/scope_fail, that
knowledge is one package and I will use tool I need depending on the
context.

>> There is also value in code readability. Seeing scope_fail will
>> immediately give you the idea that this is an error handler rather than
>> a general cleanup.
>
> I agree scope_fail is useful for the "is exception active" detection.
>
> I am guessing you're arguing that, as scope_fail may already be in use in some
> contexts due to its ability to detect when an exception is active, it might be
> useful to allow the user to extend it to add more failure conditions.
>
> What I was thinking was on the case that the user was trying to use scope_fail
> without exceptions active: I don't see the point. They may as well use a plain
> scope_guard and have their error condition checked inside the lambda. Or, as
> argued above, not do any checking and dismiss when success has been assured.

Well, I guess, that comes down to preferences then. If I'm writing code
that doesn't use exceptions to indicate error, I would still prefer to
use scope_fail to handle errors, even if to just make the code more
self-documenting.

>>> Can this simply be QoI? The control variable of a dismissable scope guard
>>> that isn't dismissed can itself be garbage-collected after optimisation
>>> passes such as constant propagation and dead code elimination.
>>
>> I don't think the QoI argument is realistic with current or forseeable
>> compiler tech, at least I don't see such optimizations taking place with
>> unique_lock vs. lock_guard in real code bases beyond some simple cases.
>> And I'd like to emphasize that in my experience unconditional scope
>> guards are much more prevalent to the dismissable ones.
>
> I would still argue for the compiler optimisation. Quite frankly, I'm not
> seeing how difficult it is: a variable that is only written to once, with a
> known constant value, need not be stored in memory anywhere. The compiler can
> constant-propagate it to the places where it's used, meaning there shouldn't
> be any conditionals in the code.
>
> Additionally, how costly is it if the compiler fails to do this? How much
> real-world benefit do we get with this simpler class? Contrast that with how
> much we pay for having it: it's a cost for implementers, it's a cost for
> developers to learn that this exists, and it's a cost for reviewers to
> understand what it does.
>
> Take the example of scope_lock and unique_lock: without looking up the
> reference documentation, I can't tell you the difference between them and why I
> should use one and not the other. I can probably guess based on the name.

Well, since I'm using both lock_guard and unique_lock (probably, at the
60/40 ratio, meaning 60% of the time I'm using lock_guard), I have no
problem remembering which is what. I guess, if you don't want to bother
remembering, you could just always use unique_lock (and, similarly,
scope_exit) and call it a day. But for optimization maniacs like myself,
I would prefer to have both lock_guard and scope_final. :)

And no, I don't trust the compiler optimizing away the difference. They
don't do it currently, and lock_guard/unique_lock exist for more than a
decade now, so I don't have high hopes for the future. Don't get me
wrong, there probably are reasons why they don't do it, but the point is
it is beneficial to explicitly write code the way you want it rather
than to hope for the compiler to make it right.

Received on 2023-04-08 10:55:53