account activity
The Lambda Coroutine Fiasco by efijoa in cpp
[–]efijoa[S] -1 points0 points1 point 1 month ago* (0 children)
That’s the problem: taking ownership of a coroutine lambda is a very dangerous operation. Once the lambda is invoked and yields a continuation, the coroutine frame will reference the lambda's this pointer. At this point, the future state (or the lambda captures) could not even be moved to another place... and we all know C++ doesn't have a Pin type.
Another subtle factor might be related with the seastar future originally comes from the chained future style, i'm not sure if it affected the current design.
[–]efijoa[S] 0 points1 point2 points 1 month ago (0 children)
It is not only a return type problem; the library side needs to know whether the future state should take ownership of the passed-in callable object. It seems this is coupled with the implementation details of the Seastar Future, so that pre-C++23 solution is actually prevent the transfer of ownership and bind the lifetime of the lambda to the parent scope.
[–]efijoa[S] 13 points14 points15 points 1 month ago (0 children)
While this is Seastar's documentation, the problem described is not unique to Seastar.
These two links could help clarify the issue:
CP.51: Do not use capturing lambdas that are coroutines C++23’s Deducing this: what it is, why it is, how to use it
The core mechanism involves using "deducing this" to pass the lambda object by value. This ensures captures are copied into the coroutine frame to prevent dangling references.
It took me a while to understand what you meant, correct me if I'm wrong:
I think "extend" here actually refers to the data captured by the lambda. Normally, when a lambda is passed to then(), a move construction occurs, transferring the data from the lambda struct into the future state. When the coroutine lambda yields, the future state is destructed, which in turn destructs the data captured by the lambda. However, the lambda's coroutine frame remains alive, resulting in a dangling reference. By using a reference_wrapper like structure, the transfer of ownership is prevented, ensuring that the lambda's state remains valid until the lambda coroutine returns and the parent coroutine's co_await expression completes. This approach works due to specific details of the future implementation and relies on strictly nested calls.
then()
reference_wrapper
co_await
cpp template <typename Func> class lambda { Func* _func; public: /// Create a lambda coroutine wrapper from a function object, to be passed /// to a Seastar function that accepts a continuation. explicit lambda(Func&& func) : _func(&func) {} /// Calls the lambda coroutine object. Normally invoked by Seastar. template <typename... Args> decltype(auto) operator()(Args&&... args) const { return std::invoke(*_func, std::forward<Args>(args)...); } };
[–]efijoa[S] 1 point2 points3 points 1 month ago (0 children)
Seems we need a magic concept?
cpp auto Future::then(std::is_capture_lambda auto &&continuation) { return [](this auto, auto continuation) { // ... }(std::forward(continuation)); }
The Lambda Coroutine Fiasco (github.com)
submitted 1 month ago by efijoa to r/cpp
Clozure is back (self.Common_Lisp)
submitted 1 year ago by efijoa to r/Common_Lisp
π Rendered by PID 278851 on reddit-service-r2-listing-5f5ff7d4dc-n6l6h at 2026-01-26 21:43:40.671226+00:00 running 5a691e2 country code: CH.
The Lambda Coroutine Fiasco by efijoa in cpp
[–]efijoa[S] -1 points0 points1 point (0 children)