Re: [capy] Andrzej's feedback
Andrzej Krzemienski via Boost <[email protected]> Wed, 8 Jul 2026 02:19:39 +0200
| Newsgroups | gmane.comp.lib.boost.devel |
|---|---|
| Message-ID | <CAOenAXgB2o8D5zK1TbVDOAvJwti6NaTnXCXxRSogGyzEGenivQ@mail.gmail.com> |
--00000000000061512906560e77bc Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable wt., 7 lip 2026 o 00:58 Vinnie Falco <[email protected]> napisa=C5=82(= a): > On Mon, Jul 6, 2026 at 2:53=E2=80=AFPM Andrzej Krzemienski <akrzemi1@gmai= l.com> > wrote: > >> Slightly as a nit-pick, I have just learnt that you also have to study >> the not-proposed Boost.HTTP to be able to review the concept BufferSing,= as >> it has no real model in Capy or Corosio. >> > > Yeah, that's fair. And I think maybe we can include an example or > something so there is some review surface. > > >> Why does the doc page describing the launching of coroutines ( >>> https://develop.capy.cpp.al/capy/4.coroutines/4b.launching.html) have a >>> red warning box? >>> >> > Well the two-call syntax can be abused. Don't do that. > > >> Some people do not like thread_local based on its implementation >> difficulties: requires dynamic memory allocation (and no custom allocato= r >> can be provided), is not implementable on some architectures. >> > > Okay but that's for implementors. The user doesn't have to worry about > that. If thread_local is not available on a particular architecture, the > implementation can fall back to the global allocator. Or in more practica= l > terms it simply uses a plain global variable. It turns out that the > platforms without thread_local also tend to not have threads (P4182R2 whi= ch > I can't seem to find at the moment... Mungo?) > > >> My discomfort is not about the feature itself, but how it is used. The >> usage is based on the assumption that the read from the variable happens >> (1) immediately after the write (no intervening accesses) and (2) on the >> same thread. And since you cannot enforce that, you have to trust the us= er, >> and maybe even trust your luck. >> > > We *can* guarantee it. Section 8.3: > > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4172r1.pdf > > >> But because this hack is made to move the complexity out of the user's >> sight, the user will not cooperate (they do not know that they have to). >> > > The user doesn't have to cooperate. The launch function has the burden. > P4172 describes three audiences: > > 1. Application developer > 2. Framework author > 3. I/O library author > > The Framework author has the responsibility of making sure that the launc= h > functions and task types they create follow the rules. These authors are > fewer in number with a higher level of skill. The expectations are > reasonable. > > >> I am not even sure how this can be implemented for non-task IoAwaitables >> when in a thread executing the coroutine may be different than the threa= d >> resuming the coroutine, in a thread pool executor. >> > > Non-task awaitables do not have an associated coroutine, so they don't > have to handle it. They just put their state into the calling coroutines > frame, without requiring an allocation. These are written by I/O library > authors (group 3 above). Corosio is full of them. read_some_awaitable, an= d > so on. > > >> Also, as with any other hacks, they work under the assumption that no-on= e >> else is doing their own hacks at the same time. Boost.LEAF uses the TLS >> hack, and it only works until you have to interoperate with a coroutine >> library. >> > > There is no monolithic "TLS hack." It is not some light switch that is > turned on and off. Boost.LEAF and Capy each use their own thread local > variables to achieve their ends. Since the variables have different > linkages, they are separate from each other and work together Just Fine. > > Show me the specific interaction where you think these libraries do not > compose? > > >> In fact, I wish that the problem of environment propagation were >> addressed by a dedicated language feature that indicates the intention >> explicitly and allows the compiler to verify the correct usage. >> > > Changing the language should be DIFFICULT and EARNED. Engineers are too > hasty to beg the language for features to make their lives easier. Note, = we > did not go running hat in hand to wg21 saying "please solve this in the > language." We especially do not say "we need co_yield to act as a final > suspend." > > Instead, we come up with our own solution which does not require changes > to the language. It is not perfect, but it gives 16.3 million potential > users of networking a path to use coroutines for composition, instead of > callbacks. And then we can get field experience will may LATER justify a > change to the language. But only after we have at least 9 years under our > belt. > > >> My discomfort is not about the strangeness of the notation but about how >> easy it is to misuse it. The red warning box in the docs confirms this. >> BTW, the example in the warning box is wrong. That code would not compil= e >> (and rightly so). But there are others that would compile and silently g= et >> a different behavior. >> > > You say "there are others" plural. But only give one example. Maybe it is > a legitimate example but the way you phrase it implies a wider scope than > exist. Please enumerate actual problems so they can be engaged one by one= , > and not unfalsifiable generalizations. > > 3. Having to use pass they stop_token via await_ready (and therefore >> risk UB when stop_token is queried before the first suspend). >> > > What? Show the undefined behavior you think is happening, please. > > >> I imagine a coroutine where a part of its body is executed >>> immediately, without suspension. I can imagine a stop being requested f= rom >>> a different thread executing a different continuation. Say, calling >>> .cancel() on some IO object. >>> >> > You can imagine all you like but please, show concrete examples. The > example you just gave, calling cancel() on "some I/O object" from a > different thread, is undefined behavior. > > ALL I/O objects in Corosio are NOT THREAD SAFE. You cannot access them > concurrently. > > Please show a concrete example of undefined behavior. > > >> I did not mean C++26 executors as the alternative. I was thinking more >> in the vein of https://github.com/ClickHouse/silk. >> > > Stackful coroutines ("fiber" in silk parlance) are wonderful. And Nat > Goodspeed should not have waited over twelve years to get them in the > standard. They do not replace stackless coroutines, nor do they compete > with them. They are a legitimate tool which solves the same problem with = a > different set of tradeoffs. > > C++ needs them, just as much as it needs frame-opaque stackless > coroutines. And I would argue the language needs frame visible coroutines > as well. This is not contested and I have written a paper saying so: > > *Benefits of Frame-Visible Coroutines for Senders* > https://isocpp.org/files/papers/P4166R0.pdf > > However, they are unsuited to a large class of I/O problems, networking i= n > particular. > > Jamie, do you want to build your system on fibers, or stackless coroutine= s? > > >> I am in favour of doing the right thing rather than doing what the >> Standard does. They can of course coincide, but the guidance from the >> standard alone is insufficient motivation. >> > > That's a false premise. In this case the Right thing and the Standard > thing are the same thing: error_code for common outcomes and transient > states, and exceptions for exceptional outcomes. > > >> Who said they are supposed to be "errors"? `error_code` is just a label. >>> You are attaching semantic significance to the type name. >>> >> >> I am not sure if you are serious. I indeed attach semantic significance >> to the type name. Why did you call the type providing access to a UDP >> socket in Corosio `udp_socket`? You could have called it `sun_flower` an= d >> then insist that people should not attach semantic significance to type >> names. >> > > Of course I am serious. And I did not choose the name error_code. It is > what it is, and it cannot be changed. That said, this is how it is being > used. To argue "you shouldn't use it that way" is not a serious debate wh= en > the customs have already been adopted. And I would say, that returning > distinguishable, successful outcomes from error_code is fully in scope. > Again I point to Boost.System: > > > https://github.com/boostorg/system/blob/bc7c00fa67501ceadfde8e92083550234= 0e8b899/include/boost/system/detail/error_code.hpp#L287 > > Why does `bool failed()` exist, if according to you there should only be > one value of "success?" Was Peter Dimov wrong? > > >> In this case I do not buy the "ASIO got that right" argument. >>> >>> Asio doesn't have any dual-stream interfaces. >>> >> >> ASIO uses type error_code to signal non-errors. >> > > A quarter-century of established practice. Show me your alternative. Then > let's compare. > I am answering before going to sleep, so this may not be a complete answer that you deserve, but I do not want you to wait another day for the reply. I expressed my discomfort with the double call syntax. I chose word discomfort to convey that I am not opposed to the solution (I wouldn't be able to come up with a better one without violating other goals), but I note that unlike a lot of other features in Boost, we do not get this "easy to use correctly, hard to use incorrectly" effect. For examples of how this can be misused. One has already been provided, I think by Rainer: run_async(exec)(the_job(1, "8080")); And `the_job` may be a factory function or a getter, or a wrapper function. It is generally a reasonable thing to do, but not when the double-call syntax (with TLS under the hood) is in action and the slight misordering of the sight effects may break the system. Another example is when somebody decides to refactor the code in order not to repeat themselves: auto exec_runner =3D run_async(exec); /// ... run_all_coros(move(exec_runner), {my_job1(), my_job2(), my_job3()}); The argument of "three audiences" has been made a couple of times. I hear that there is going to be a "I/O library author". When writing a custom I/O functionality they may need to provide their own IoAwaitable. I read that such an "author has the responsibility of making sure that the launch functions and task types they create follow the rules". Can you point me to the place where these rules are written down with the level of detail necessary for the "I/O library author" to do their job correctly? The interesting case is when we have an IoAwaitable (to be associated with a coroutine) that does not have the initial suspend and does execute *part* of the coroutine's body before suspending. If in that part of the body (before the first real suspend I -- the ordinary programmer, not I/O provider) get the stop_token with `co_await this_coro`, I will get a null pointer dereference. I enclose an example that demonstrates this. Now, going back to error_code and Boost.System. If we forego the naming issue, the idea behind the error code is that your functions have weak postcondition: everything is a success. Having obtained the status code is success. Then you can inspect it and make the call on what to do next. In this view, the function std::error_category::failed(),mentioned by others would not make sense, as this would have been the decision made by someone else -- not the caller. It makes sense to use error_code at the level of stream operations. I am not sure the same technique makes sense at higher levels. Function when_all definately does not follow the Boost.System model, as it assumes any non-zero code is a failure. Function read_at_least -- using error_code to represent a precondition violation -- might be in the spirit of Boost.System, but this is so confusing: to refuse to communicate what is obviously a bug in the caller. I also think the function normalize_openssl_shutdown_read_error goes against the idea of Boost.System, as I understand it. My understanding has always been that error codes once produced stay as they are (this may be valuable information to whoever processes them at the higher level), and users use different conditions at different application levels to interpret the original code in a way suitable at their level. In contrast, normalize_openssl_shutdown_read_error discards the original value and just produces another. Regards, &rzej; --00000000000061512906560e77bc Content-Type: text/plain; charset="US-ASCII"; name="stop_token_failure.cpp" Content-Disposition: attachment; filename="stop_token_failure.cpp" Content-Transfer-Encoding: base64 Content-ID: <f_mrbb7zoy0> X-Attachment-Id: f_mrbb7zoy0 CiNpbmNsdWRlIDxib29zdC9jYXB5LmhwcD4KI2luY2x1ZGUgPGJvb3N0L2NhcHkvZXgvaW9fYXdh aXRhYmxlX3Byb21pc2VfYmFzZS5ocHA+CiNpbmNsdWRlIDxib29zdC9jYXB5L2V4L3RoaXNfY29y by5ocHA+CgojaW5jbHVkZSA8Y29yb3V0aW5lPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRl IDx1dGlsaXR5PgoKbmFtZXNwYWNlIGNhcHkgPSBib29zdDo6Y2FweTsKCi8vLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0K Ly8gQSBtaW5pbWFsICplYWdlciogY3VzdG9tIGNvcm91dGluZSB3aG9zZSBwcm9taXNlIHBhcnRp Y2lwYXRlcyBpbiB0aGUKLy8gSW9Bd2FpdGFibGUgZW52aXJvbm1lbnQgcHJvdG9jb2wgKGl0IGlu aGVyaXRzIGlvX2F3YWl0YWJsZV9wcm9taXNlX2Jhc2UpLgovLwovLyBUaGUgb25seSB0aGluZyB0 aGF0IG1ha2VzIGl0IGRhbmdlcm91cyBpcyB0aGUgZWFnZXIgaW5pdGlhbF9zdXNwZW5kLgovLy0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tCnRlbXBsYXRlPGNsYXNzIFQgPSB2b2lkPgpzdHJ1Y3QgZGVtb190YXNrCnsKICAg IHN0cnVjdCBwcm9taXNlX3R5cGUKICAgICAgICA6IGNhcHk6OmlvX2F3YWl0YWJsZV9wcm9taXNl X2Jhc2U8cHJvbWlzZV90eXBlPgogICAgewogICAgICAgIGRlbW9fdGFzayBnZXRfcmV0dXJuX29i amVjdCgpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gZGVtb190YXNrewogICAgICAgICAg ICAgICAgc3RkOjpjb3JvdXRpbmVfaGFuZGxlPHByb21pc2VfdHlwZT46OmZyb21fcHJvbWlzZSgq dGhpcyl9OwogICAgICAgIH0KCiAgICAgICAgLy8gVGhlIGhhemFyZCBsaXZlcyBoZXJlOiBlYWdl ciBzdGFydCBtZWFucyB0aGUgYm9keSBydW5zIGR1cmluZyB0aGUKICAgICAgICAvLyBjYWxsLCBi ZWZvcmUgdGhpcyBjb3JvdXRpbmUgaXMgYXdhaXRlZCBhbmQgYmVmb3JlIHNldF9lbnZpcm9ubWVu dCgpLgogICAgICAgIHN0ZDo6c3VzcGVuZF9uZXZlciBpbml0aWFsX3N1c3BlbmQoKSBub2V4Y2Vw dCB7IHJldHVybiB7fTsgfQoKICAgICAgICBzdGQ6OnN1c3BlbmRfYWx3YXlzIGZpbmFsX3N1c3Bl bmQoKSBub2V4Y2VwdCB7IHJldHVybiB7fTsgfQogICAgICAgIHZvaWQgcmV0dXJuX3ZvaWQoKSBu b2V4Y2VwdCB7fQogICAgICAgIHZvaWQgdW5oYW5kbGVkX2V4Y2VwdGlvbigpIG5vZXhjZXB0IHsg c3RkOjp0ZXJtaW5hdGUoKTsgfQogICAgfTsKCiAgICBleHBsaWNpdCBkZW1vX3Rhc2soc3RkOjpj b3JvdXRpbmVfaGFuZGxlPHByb21pc2VfdHlwZT4gaCkgbm9leGNlcHQKICAgICAgICA6IGhfKGgp CiAgICB7CiAgICB9CgogICAgZGVtb190YXNrKGRlbW9fdGFzayYmIG90aGVyKSBub2V4Y2VwdAog ICAgICAgIDogaF8oc3RkOjpleGNoYW5nZShvdGhlci5oXywge30pKQogICAgewogICAgfQoKICAg IH5kZW1vX3Rhc2soKQogICAgewogICAgICAgIGlmKGhfKQogICAgICAgICAgICBoXy5kZXN0cm95 KCk7CiAgICB9CgogICAgc3RkOjpjb3JvdXRpbmVfaGFuZGxlPHByb21pc2VfdHlwZT4gaF87Cn07 CgovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tCi8vIFNBRkU6IGEgbGF6eSBjYXB5Ojp0YXNrIHJlYWRzIHRoZSBzdG9w IHRva2VuIGZyb20gaXRzIGJvZHkuIEJ5IHRoZSB0aW1lIHRoZQovLyBib2R5IHJ1bnMsIHJ1bl9h c3luYyBoYXMgaW5zdGFsbGVkIHRoZSBlbnZpcm9ubWVudCwgc28gZW52XyBpcyBub24tbnVsbC4K Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLQpjYXB5Ojp0YXNrPD4KbGF6eV9yZWFkc19zdG9wX3Rva2VuKCkKewogICAg YXV0byB0b2tlbiA9IGNvX2F3YWl0IGNhcHk6OnRoaXNfY29ybzo6c3RvcF90b2tlbjsKICAgIHN0 ZDo6Y291dCA8PCAiW2xhenldICBzdG9wX3JlcXVlc3RlZCgpID0gIgogICAgICAgICAgICAgIDw8 IHN0ZDo6Ym9vbGFscGhhIDw8IHRva2VuLnN0b3BfcmVxdWVzdGVkKCkgPDwgIlxuIjsKICAgIGNv X3JldHVybjsKfQoKLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBIQVpBUkQ6IGFuIGVhZ2VyIGRlbW9fdGFzayB0 cmllcyB0byByZWFkIHRoZSBzdG9wIHRva2VuIGFzIGl0cyBmaXJzdCBhY3Rpb24uCi8vIFRoZSBl YWdlciBib2R5IGV4ZWN1dGVzIGR1cmluZyB0aGUgY2FsbCBiZWxvdyAtLSBiZWZvcmUgdGhlIGNv cm91dGluZSBpcyBldmVyCi8vIGF3YWl0ZWQgLS0gc28gZW52XyBpcyBzdGlsbCBudWxscHRyLgov Ly0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tCmRlbW9fdGFzazw+CmVhZ2VyX3JlYWRzX3N0b3BfdG9rZW4oKQp7CiAgICAv LyBlbnZfID09IG51bGxwdHIgaGVyZS4gSW4gaW9fYXdhaXRhYmxlX3Byb21pc2VfYmFzZTo6YXdh aXRfdHJhbnNmb3JtIHRoaXMKICAgIC8vIGhpdHMgQk9PU1RfQ0FQWV9BU1NFUlQoZW52XykgYW5k IHRoZW4gZW52Xy0+c3RvcF90b2tlbi4KICAgIGF1dG8gdG9rZW4gPSBjb19hd2FpdCBjYXB5Ojp0 aGlzX2Nvcm86OnN0b3BfdG9rZW47CiAgICBzdGQ6OmNvdXQgPDwgIltlYWdlcl0gc3RvcF9yZXF1 ZXN0ZWQoKSA9ICIKICAgICAgICAgICAgICA8PCBzdGQ6OmJvb2xhbHBoYSA8PCB0b2tlbi5zdG9w X3JlcXVlc3RlZCgpIDw8ICJcbiI7CiAgICBjb19yZXR1cm47Cn0KCmludAptYWluKCkKewogICAg Ly8gMSkgVGhlIGNvcnJlY3QgcGF0dGVybjogd29ya3MsIHByaW50cyAiZmFsc2UiLgogICAgewog ICAgICAgIGNhcHk6OnRocmVhZF9wb29sIHBvb2w7CiAgICAgICAgY2FweTo6cnVuX2FzeW5jKHBv b2wuZ2V0X2V4ZWN1dG9yKCkpKGxhenlfcmVhZHNfc3RvcF90b2tlbigpKTsKICAgICAgICBwb29s LmpvaW4oKTsKICAgIH0KCiAgICAvLyAyKSBUaGUgaGF6YXJkLiBUaGUgZWFnZXIgYm9keSBydW5z ICppbnNpZGUqIHRoaXMgY2FsbC4KICAgIHN0ZDo6Y291dCA8PCAiW2VhZ2VyXSBjYWxsaW5nIGVh Z2VyIGNvcm91dGluZSAiCiAgICAgICAgICAgICAgICAgIihpdHMgYm9keSBydW5zIGR1cmluZyB0 aGlzIGNhbGwpLi4uXG4iOwogICAgc3RkOjpjb3V0LmZsdXNoKCk7CgogICAgYXV0byB0ID0gZWFn ZXJfcmVhZHNfc3RvcF90b2tlbigpOyAvLyA8LS0gYXNzZXJ0IGZpcmVzIC8gVUIgaGFwcGVucyBo ZXJlCgogICAgLy8gUmVhY2hlZCBvbmx5IGlmIGFzc2VydGlvbnMgYXJlIGRpc2FibGVkIEFORCB0 aGUgbnVsbCByZWFkIGhhcHBlbmVkIHRvCiAgICAvLyBub3QgY3Jhc2ggLS0gZG8gbm90IHJlbHkg b24gdGhpcy4KICAgIHN0ZDo6Y291dCA8PCAiW2VhZ2VyXSByZXR1cm5lZCB3aXRob3V0IGNyYXNo aW5nICIKICAgICAgICAgICAgICAgICAiKHVuZGVmaW5lZCBiZWhhdmlvciBhbHJlYWR5IG9jY3Vy cmVkKVxuIjsKICAgICh2b2lkKXQ7CiAgICByZXR1cm4gMDsKfQo= --00000000000061512906560e77bc Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Boost mailing list -- [email protected] To unsubscribe send an email to [email protected] https://lists.boost.org/mailman3/lists/boost.lists.boost.org/ Archived at: https://lists.boost.org/archives/list/[email protected]/message/QJA3LWLNTWFWDYDIHFXW6UOVXOAR224A/ --00000000000061512906560e77bc--