On 6/26/26 17:57, Peter Dimov via Boost wrote:
(*) It also allows you to use Boost.Leaf, to borrow some ammo from the adjacent thread.
Actually, I don't think that's true at all. As I understand it (looking at just the documentation, not the source code), Leaf uses a linked list of error handlers, with a thread-local variable pointing to the head of the list. Error handlers are added and removed from the list as error handler functions enter or leave the call stack, always at the head of the list.When an error is created, Leaf walks the list, stopping at the first error handler that can store and handle the error. The actual data structure might be a bit different, but that seems to be the basic idea. The fundamental assumption is a LIFO order of error handler function invocations on the call stack. This assumption breaks completely with coroutines, even in a completely single-threaded program. Coroutine A creates an error handler (i.e. calls leaf::try_handle_some), which goes to the head of the list. Coroutine A co_awaits. Coroutine B resumes. Coroutine B creates its own error handler (calls leaf::try_handle_some), which also goes to the head of the list. Coroutine B co_awaits. Coroutine A resumes. Coroutine A raises an error. The error object gets passed to coroutine B's error handler, which is at the head of the list. The only way LEAF can ever work with coroutines is if the coroutines behave like ordinary functions, one finishing entirely before the next one starts. (Or leaf::try_capture_all at the point where the error is created, which bypasses all of that by carrying the error object in the leaf::result, but that's both inefficient and unergonomic.) -- Rainer Deyke - rainerd@eldwood.com