Boost logo

Boost :

From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2023-04-07 12:55:41


czw., 6 kwi 2023 o 23:51 Andrey Semashev via Boost <boost_at_[hidden]>
napisał(a):

> On 4/6/23 21:26, Andrzej Krzemienski via Boost wrote:
> > Hi Everyone,
> > It is my understanding that the reason scope_fail was left to die in the
> > C++ Extensions for Library Fundamentals v3 was that it is not
> > implementable.
>
> I'm not sure what you mean in the "left to die" part. Do you mean that
> these facilities are being deprecated?
>

There are two motivations for putting something into a TS. One is to
encourage vendors to implement the feature and gather usage and deployment
experience. The other is to postpone the addition of the feature or to
politely say that it is not wanted in the Standard. I *believe* this is the
case with the subset of scope guards. I have seen no movement towards
moving scope_fail into the Standard. and not moving them into the standard
in reality means abandoning them.

>
> > One cannot detect if the scope is being left due to an
> > exception thrown from within the scope. Observing the number of uncaught
> > exceptions in the constructor and in the destructor will not work, given
> > that we now have coroutines that can be suspended and then resumed in
> > another thread (with a different number of uncaught exceptions), or even
> in
> > the same thread but at some later point, when the number of uncaught
> > exceptions has changed.
> >
> > The enclosed example illustrates how a scope_fail fails to call the
> > callback when an exception is thrown from a coroutine. It uses Lewis
> > Baker's CppCoro implementation of a generator.
> >
> > The only reliable way to call a callback when the scope is left due to an
> > exception is through using the explicit call to `deactivate()` function.
> It
> > is more verbose, but reliable.
>
> I must say I have no experience with coroutines, but my understanding is
> that they are basically incompatible with any mechanism that relies on
> thread-specific state, including the uncaught exceptions counter.

Indeed. Note that the example I provided uses just one thread. The problem
is the suspension itself.

> Thus I
> wouldn't say scope_success/scope_fail are unimplementable - they clearly
> are - but that they are incompatible with coroutines. That is, these
> scope guards will work as expected as long as you don't switch
> coroutines within the guarded scope.
>

Maybe this is just a question of the choice of words.
But the docs do not present the situation in this way.

"Although it is possible to specify arbitrary condition function objects,
typically scope_success
<https://lastique.github.io/scope/libs/scope/doc/html/boost/scope/scope_success.html>
invokes its action when the scope is left normally (i.e. not via an
exception) and scope_fail
<https://lastique.github.io/scope/libs/scope/doc/html/boost/scope/scope_fail.html>
should typically be used to handle errors, including exceptions."

This guarantee (when scope is exited not normally) cannot be satisfied in
general. One cannot use it in a coroutine: directly or indirectly. One
might not even know the context.

"By default, scope_success
<https://lastique.github.io/scope/libs/scope/doc/html/boost/scope/scope_success.html>
will invoke its action if it is destroyed normally, scope_fail
<https://lastique.github.io/scope/libs/scope/doc/html/boost/scope/scope_fail.html>
- if it is destroyed due to an exception being thrown."

(BTW, The synopsis in
https://lastique.github.io/scope/libs/scope/doc/html/boost/scope/scope_fail.html
does not indicate that there is any default Cond.)

This is not true when a scope guard is used across coroutine suspensions:
by default [...] scope_fail is not destroyed due to exception being thrown.
The reality is, it is destroyed based on the comparison of two measurements
of the number of uncaught exceptions, potentially measured in different
threads.

> I admit this is a notable limitation, and I will document it. But I do
> not consider this limitation fatal, as there is plenty code out there
> that doesn't use coroutines - I'd even say, much more code than that does.
>

This is one way of looking at it: that the problem is rare. A different way
is to say that if something works in 99% of the cases and fails only in 1%,
we have a dangerous situation, as we are unprepared when the 1% case
happens.

> Also, I forgot to mention that Boost.Scope's scope_success/scope_fail
> support custom failure predicates which may not rely on the exception
> state at all.

Can it be used to fix the coroutine case? (That is to detect that the scope
is left due to an exception being thrown?)

Regards,
&rzej;


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