Skip to content

Commit 6027483

Browse files
committed
update docs to reflect current coro
1 parent 96dcd21 commit 6027483

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

tutorials/coroutines.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[Coroutines](https://en.cppreference.com/w/cpp/language/coroutines) are an underutilized feature of C++20 that not many understand. Under the hood, they are very complex, but luckily Geode makes it quite simple for you. Geode lets you leverage the power of coroutines to write clean asynchronous code, tackle Result propagation, and build Python-style generators with ease.
44

5-
## Task and CoTask
5+
## Task
66

77
For most asynchronous tasks, Geode provides the Task class. See [`Tasks`](/tutorials/tasks) for more information. Any function that returns a Task can be converted into a coroutine by simply using `co_await` on a different task.
88

@@ -37,22 +37,36 @@ Task<std::string, int> someTask() {
3737
}
3838
```
3939

40-
One problem that stems from using Task for asynchronous handling is that it has the `[[nodiscard]]` attribute. Often times, you want a coroutine without any given return value, which leads to annoyances with compiler warnings. `coro::CoTask` is the solution to this, as it's a discardable wrapper around Task:
40+
## Spawning from regular functions
41+
42+
The correct way to launch a coroutine from a regular function is to use `coro::spawn`. You can do this in a number of ways:
4143

4244
```cpp
43-
#include <Geode/utils/web.hpp>
44-
#include <Geode/utils/coro.hpp>
45+
// Spawn from a Task via operator<<
46+
coro::spawn << someTask();
4547

46-
coro::CoTask<void> logResponseCode() {
47-
auto req = web::WebRequest();
48-
auto res = co_await req.get("https://google.com");
48+
// Spawn from a coroutine via operator<<
49+
coro::spawn << [] -> Task<void> {
50+
co_return;
51+
};
4952

50-
log::info("Response code: {}", res.code());
51-
}
53+
// Spawn from a Task via operator()
54+
coro::spawn(someTask());
5255

53-
logResponseCode(); // No warning
56+
// Spawn from a coroutine via operator()
57+
coro::spawn([] -> Task<void> {
58+
co_return;
59+
});
5460
```
5561
62+
You can use whichever syntax you prefer. It is crucial to use `coro::spawn` on coroutines that return Task to prevent it from canceling when it goes out of scope. In order to prevent Task's `[[nodiscard]]` attribute from getting in the way, using `coro::spawn` on a Task-based coroutine will return a one-item tuple containing the Task. If you wish to get the underlying Task out of the spawn, you can do so simply:
63+
64+
```cpp
65+
auto [task] = coro::spawn << someTask();
66+
```
67+
68+
## $async
69+
5670
Creating a new function for just the asynchronous bits might get tedious. Luckily, you don't have to with the `$async` macro:
5771

5872
```cpp
@@ -68,7 +82,7 @@ void logResponseCode(std::string const& url) {
6882
}
6983
```
7084
71-
Under the hood, `$async` sets a coroutine lambda and immediately invokes it. Any arguments within the macro body are lambda captures, so you could just as easily put `=` in there too.
85+
Under the hood, `$async` sets a coroutine lambda and immediately spawns it via `coro::spawn`. Any arguments within the macro body are lambda captures, so you could just as easily put `=` in there to. It is not recommended to capture by reference as it's not guaranteed that the lambda will finish before the references go out of scope.
7286
7387
## Result propagation
7488
@@ -185,4 +199,4 @@ for (int num : range(0, 10).filter([](int n) { return n % 2 == 0; })) {
185199
}
186200
```
187201

188-
You can use the `coro::makeGenerator` function to construct a generator based on a vector.
202+
You can use the `coro::makeGenerator` function to construct a generator based on a vector or a CCArray.

0 commit comments

Comments
 (0)