czw., 9 lis 2023 o 15:09 Klemens Morgenstern < klemensdavidmorgenstern@gmail.com> napisał(a):
On Thu, Nov 9, 2023 at 9:41 PM Andrzej Krzemienski via Boost
wrote: In Boost.Cobalt (formerly Boost.Async) we have function cobalt::race (formerly select()) that takes a range of awaitables `p` and returns an awaitable capable on awaiting on one of the elements of `p`:
https://www.boost.org/doc/libs/develop/libs/cobalt/doc/html/index.html#race-...
Example:
``` promise<string> talk_to_server_1(); promise<string> talk_to_server_2(); promise<string> timeout_with_default();
vector
servers = { talk_to_server_1(), talk_to_server_2(), timeout_with_default() }; pair ans = co_await race(servers); ``` This obviously cannot work when the input range passed to `race` is
empty.
This example doesn't help, because this should obviously use the variadic version.
The reason to use the ranged one is for when you have another component dictating what elements to listen to.
try { vector
servers; for (const auto & server : config.get_servers()) servers.push_back(talk_to_server(server)); co_await race(servers); } catch(std::exception &) { // handle errors from running any server }
That means the code using the ranged version is likely unaware of the actual value, because there's a very high likelihood it's not known at compile time.
Thanks Klemens. This is very useful information (when to use which overload), and I recommend that it should be put in the documentation. Stil, I do not feel convinced. Your example illustrates, I think, the situation where an untrusted external input is passed unvalidated to the guts of the program. I would never like to encourage or support this way of writing servers. Of course, people will still do it, and it is prudent of you to be prepared for it, but I would still strongly insist that your library calls this usage a bug: that is something that the programmer should fix as soon as they can. It doesn't prevent you from throwing exceptions, but you have an opportunity to additionally discourage the use like this (via warnings, crashes in debug mode, additional control flows in debugger).
Hi Everyone, I would like to discuss one correctness aspect of Boost.COBALT. We have this list and the Slack channel, so I am not sure which place is better. Let me do it here.
I don't see why this is a correctness issue and not a design choice. When is it correct to use an exception?
To some extent, this is your choice as a library author. But I am trying to set up a guideline or a policy applicable to a range of libraries. The uncontroversial circumstance that warrants a throw, is when a function cannot deliver its promise, but the caller couldn't have known about it when calling a function: ``` File f ("C:/folder/filename.cfg"); ``` Here I checked that the file existed one millisecond ago. I requested for it to be open, but the OS determined that the file is no longer there. There was nothing I can do to guarantee that the file would be openable. The case with `race` is different. There is a very simple way of checking the empty-range, and it never can produce a meaningful result. Regards, &rzej;